Golang HTTP服务器等待数据发送给客户端。

huangapple go评论70阅读模式
英文:

Golang HTTP server wait for data to send to client

问题

我正在创建一个类似于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) {
        // 在这里等待,直到对w进行写入
        // 或者超时,我们可以在每次写入后重置此超时
    })

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

I am creating a streaming API similar to the Twitter firehose/streaming API.

As far as I can gather this is based on HTTP connections that are kept open and when the backend gets data it then writes to the chucked HTTP connection. It seems that any code I write closes the HTTP connection as soon as anything connects.

Is there a way to keep this open at all?

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))
}

答案1

得分: 10

当你想要在某个事件之后而不是立即将HTTP响应发送给客户端时,这被称为长轮询

以下是带有客户端断开连接时请求取消的长轮询的简单示例:

package main

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

func longOperation(ctx context.Context, ch chan<- string) {
    // 模拟长时间操作。
    // 将其更改为超过10秒以获取服务器超时。
    select {
    case <-time.After(time.Second * 3):
        ch <- "成功的结果。"
    case <-ctx.Done():
        close(ch)
    }
}

func handler(w http.ResponseWriter, _ *http.Request) {
    notifier, ok := w.(http.CloseNotifier)
    if !ok {
        panic("预期 http.ResponseWriter 是一个 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, "服务器忙碌。")
    case <-notifier.CloseNotify():
        fmt.Println("客户端已断开连接。")
    }
    cancel()
    <-ch
}

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

URLs:

  1. https://stackoverflow.com/questions/20793568/golang-anonymous-struct-and-empty-struct.
  2. https://stackoverflow.com/questions/26769626/send-a-chunked-http-response-from-a-go-server.
  3. Go并发模式:Context.

Gists:

  1. [Golang长轮询示例][5].
  2. [带有请求取消的Golang长轮询示例][6].
英文:

When you want to send HTTP response to client not immediately but after some event, it's called long polling.

Here's simple example of long polling with request cancellation on client disconnect:

package main

import (
    &quot;context&quot;
    &quot;fmt&quot;
    &quot;net/http&quot;
    &quot;time&quot;
)

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

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

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

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

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

URLs:

  1. https://stackoverflow.com/questions/20793568/golang-anonymous-struct-and-empty-struct.
  2. https://stackoverflow.com/questions/26769626/send-a-chunked-http-response-from-a-go-server.
  3. Go Concurrency Patterns: Context.

Gists:

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

huangapple
  • 本文由 发表于 2017年6月21日 21:00:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/44676895.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定