我正在创建类似于Twitter firehose / streaming API的流API。
据我所知,这是基于保持打开状态的HTTP连接的,当后端获取数据时,它会写入被阻止的HTTP连接。 看来,我编写的任何代码都会在任何东西连接后立即关闭HTTP连接。
有没有办法保持这种开放?
1 2 3 4 5 6 7 8 9 10 | 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的最佳方法是什么?
- 您可以尝试将其放入具有选择语句的无限for循环中,这样您就可以捕获发生的任何错误以关闭任何错误的连接
- 阻止任何功能的方式相同。 您需要与其他goroutine协调,将其传递给ResponseWriter,然后等待其完成。 如果您为此运行了goroutine,则必须已经有某种模式来调度和等待它们。
- 好的,这很有意义,每个新的HTTP连接也会启动goroutine吗?
- 是的,每个连接处理程序都在自己的goroutine中; goroutines是Go处理并发的方式。
当您不希望在某个事件之后立即向客户端发送HTTP响应时,称为长轮询。
这是一个长轮询的简单示例,该轮询在客户端断开连接时取消请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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) } |
网址:
要点:
- 谢谢。 它与我最终得到的结果相似。 我要解决的问题是,如果客户端在长时间操作期间断开连接,会发生什么情况
-
检查
CloseNotifier golang.org/pkg/net/http/#CloseNotifier和context 包blog.golang.org/context - 香港专业教育学院更新了我的答案,使它更完整。
- WebSockets是长轮询的现代替代方案...连接保持打开状态,因此可以从打开的Websocket上的客户端或服务器端发送流量
- @berserkk很好,我没有考虑使用上下文,但是很好地整理了它!