【问题标题】:Golang HTTP server wait for data to send to clientGolang HTTP 服务器等待数据发送到客户端
【发布时间】:2017-11-24 09:42:52
【问题描述】:

我正在创建一个类似于 Twitter firehose/streaming API 的流式 API。

据我所知,这是基于保持打开状态的 HTTP 连接,当后端获取数据时,它会写入被卡住的 HTTP 连接。似乎我编写的任何代码都会在任何连接后立即关闭 HTTP 连接。

有没有办法让它保持打开状态?

func startHTTP(pathPrefix string) {
    log.Println("Starting HTTPS Server")
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // Wait here until a write happens to w
        // Or we timeout, we can reset this timeout after each write
    })

    log.Print("HTTPS listening on :5556")
    log.Fatal(http.ListenAndServeTLS(":5556", pathPrefix+".crt", pathPrefix+".key", nil))
}

【问题讨论】:

  • 如果您不想关闭连接,请不要从处理程序返回。处理程序是“处理”连接的对象。
  • 对,所以它到达函数的末尾并返回并关闭连接。 “阻塞”函数并能够从另一个 goroutine 写入 w 的最佳方法是什么?
  • 您可以尝试将其放入具有 select 语句的无限 for 循环中,这样您就可以捕获发生的任何错误以关闭任何错误的连接
  • 在任何函数中阻止的方式相同。您需要与其他 goroutine 协调,将 ResponseWriter 传递给它,然后等待它完成。如果你有为此运行的 goroutine,你必须已经有某种模式来调度和等待它们。
  • 是的,每个连接处理程序都在它自己的 goroutine 中; goroutines 是 Go 处理并发的方式。

标签: go


【解决方案1】:

当您不想立即向客户端发送 HTTP 响应时,而是在某个事件之后,它被称为long polling

这是一个在客户端断开连接时取消请求的长轮询的简单示例:

package main

import (
    "context"
    "fmt"
    "net/http"
    "time"
)

func longOperation(ctx context.Context, ch chan<- string) {
    // Simulate long operation.
    // Change it to more than 10 seconds to get server timeout.
    select {
    case <-time.After(time.Second * 3):
        ch <- "Successful result."
    case <-ctx.Done():
        close(ch)
    }
}

func handler(w http.ResponseWriter, _ *http.Request) {
    notifier, ok := w.(http.CloseNotifier)
    if !ok {
        panic("Expected http.ResponseWriter to be an http.CloseNotifier")
    }

    ctx, cancel := context.WithCancel(context.Background())
    ch := make(chan string)
    go longOperation(ctx, ch)

    select {
    case result := <-ch:
        fmt.Fprint(w, result)
        cancel()
        return
    case <-time.After(time.Second * 10):
        fmt.Fprint(w, "Server is busy.")
    case <-notifier.CloseNotify():
        fmt.Println("Client has disconnected.")
    }
    cancel()
    <-ch
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe("localhost:8080", nil)
}

网址:

  1. Golang : anonymous struct and empty struct
  2. Send a chunked HTTP response from a Go server
  3. Go Concurrency Patterns: Context

要点:

  1. Golang long polling example
  2. Golang long polling example with request cancellation

【讨论】:

  • 谢谢。这与我最终得到的结果相似。我想要解决的是如果客户端在 longOperation 期间断开连接会发生什么
  • 我已经稍微更新了我的答案以使其更完整。
  • WebSockets 是长轮询的现代替代方案......连接保持打开状态,因此可以从打开的 websocket 上的客户端或服务器端发送流量
  • @berserkk 不错,我没有考虑过上下文的使用,但这很好地整理了它!
猜你喜欢
  • 2019-07-24
  • 2022-01-12
  • 2013-04-11
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多