服务器发起的请求

FPG*_*PGA 11 http go http2

我知道HTTP是一种请求 - 响应协议.简而言之,我的问题是客户端向服务器发出请求以启动长时间运行的进程,并且我想通过包含进度信息的简单JSON消息通知客户端进度.

在HTTP/1.1中,我知道我可以使用WebSocket或服务器发送的事件(SSE)或长轮询.

现在我知道HTTP/2还不支持WebSocket.

我的问题是,通过HTTP/2处理此类事情的最佳方式是什么?

在HTTP/2中是否有任何我不知道的新事物来处理服务器发起的请求?

如果重要的话,我正在使用Go语言.

End*_*age 9

在websockets之前,我们进行了轮询.这实际上意味着定期向客户端(每隔几秒,或对您的应用程序有意义的任何时间段),向服务器发出请求以找出作业的状态.

许多人使用的优化是"长"轮询.这涉及让服务器接受请求,并在服务器内部检查更改,并在没有服务器时休眠,直到达到特定超时或发生所需事件,然后将消息发送回客户端.

如果达到超时,则关闭连接并且客户端需要发出另一个请求.服务器代码看起来如下所示,假设函数根据其名称和签名做了明智的事情:

import (
    "net/http"
    "time"
)

func PollingHandler(w http.ResponseWriter, r *http.Request) {
    jobID := getJobID(r)
    for finish := 60; finish > 0; finish-- { // iterate for ~1 minute
        status, err := checkStatus(jobID)
        if err != nil {
            writeError(w, err)
            return
        }
        if status != nil {
            writeStatus(w, status)
            return
        }
        time.Sleep(time.Second) // sleep 1 second
    }
    writeNil(w) // specific response telling client to request again.
}
Run Code Online (Sandbox Code Playgroud)

处理超时的更好方法是使用上下文包并创建具有超时的上下文.这看起来像是这样的:

import (
    "net/http"
    "time"
    "golang.org/x/net/context"
)

func PollingHandler(w http.ResponseWriter, r *http.Request) {
    jobID := getJobID(r)
    ctx := context.WithTimeout(context.Background(), time.Second * 60)
    for {
        select{
        case <-ctx.Done():
            writeNil(w)
        default: 
            status, err := checkStatus(jobID)
            if err != nil {
                writeError(w, err)
                return
            }
            if status != nil {
                writeStatus(w, status)
                return
            }
            time.Sleep(time.Second) // sleep 1 second
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

第二个版本将在更可靠的时间内返回,特别是在checkStatus可能是较慢的呼叫的情况下.

  • 通常,不希望HTTP服务器能够向客户端发出请求。很多时候,您会发现客户端被防火墙防火墙,NAT后或其他无法访问的情况。HTTP2很酷,但是除非您使用它的一些新功能(鉴于Go的实现目前还很原始,这似乎不太可能),否则您可以坚持使用HTTP 1.1并使用良好的旧websocket。在Go中准备就绪时,升级到HTTP2几乎肯定非常简单。 (2认同)

ann*_*neb 5

您可以考虑使用HTML5文本/事件流即服务器端事件(SSE).问题中提到了SSE,http2会不会很好用?

关于SSE的一般文章

(IE是目前唯一不支持SSE的浏览器)

在下面的文章中,http2 push与SSE结合使用.文档被推送到客户端缓存中,SSE用于通知客户端可以从其缓存中检索哪些文档(=通过单个http2连接的服务器启动的请求):

SSE的基础知识:在服务器端,您从以下开始:

Content-Type: text/event-stream\n\n
Run Code Online (Sandbox Code Playgroud)

然后每次要向您发送的客户端发送更新

data: { "name": "value", "othername": "othervalue" }\n\n
Run Code Online (Sandbox Code Playgroud)

完成后,在关闭连接之前,您可以选择发送:

retry: 60000\n\n
Run Code Online (Sandbox Code Playgroud)

指示浏览器在60000毫秒后重试新连接

在浏览器中,连接如下所示:

var URL = "http://myserver/myeventstreamer"
if (!!window.EventSource) {
    source = new EventSource(URL);
} else {
    // Resort to xhr polling :(
    alert ("This browser does not support Server Sent Events\nPlease use another browser") 
}

source.addEventListener('message', function(e) {
  console.log(e.data);
}, false);

source.addEventListener('open', function(e) {
  // Connection was opened.
}, false);

source.addEventListener('error', function(e) {
  if (e.readyState == EventSource.CLOSED) {
    // Connection was closed.
  }
}, false);
Run Code Online (Sandbox Code Playgroud)