dty5753 2015-06-15 00:40
浏览 36
已采纳

服务器启动的请求

I know that HTTP is a request-response protocol. My problem, in short, is that a client makes a request to the server to start a long running-process, and I want to inform the client of the progress with a simple JSON message containing progress info.

In HTTP/1.1 I know that I could use a WebSocket or server-sent events (SSE) or long polling.

Now I know that HTTP/2 does not support WebSocket yet.

My question is, what is the optimal way to handle such things over HTTP/2?

Are there any new things that I am not aware of to handle server-initiated requests in HTTP/2?

I am using the Go language, if that matters.

  • 写回答

3条回答 默认 最新

  • douzhan8652 2015-06-15 04:33
    关注

    Before websockets we had polling. This literally means having the client periodically (every few seconds, or whatever time period makes sense for your application), make a request to the server to find out the status of the job.

    An optimization many people use is "long" polling. This involves having the server accept the request, and internally to the server, check for changes, and sleep while there are none, until either a specific timeout is reached or the desired event occurs, which is then messaged back to the client.

    If a timeout is reached, the connection is closed and the client needs to make another request. The server code would look something like the following, assume the functions do sensible things based on their names and signatures:

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

    A better way to handle the timeout would be to use the context package and create a context with a timeout. That would look something like:

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

    This second version is just going to return in a more reliable amount of time, especially in the case where checkStatus may be a slower call.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 js调用html页面需要隐藏某个按钮
  • ¥15 ads仿真结果在圆图上是怎么读数的
  • ¥20 Cotex M3的调试和程序执行方式是什么样的?
  • ¥20 java项目连接sqlserver时报ssl相关错误
  • ¥15 一道python难题3
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试