简体   繁体   English

请求取消或超时时如何从http处理程序返回

[英]How to return from an http handler when the request is cancelled or times out

I'm doing sse , the important code is: 我正在做sse ,重要的代码是:

   var clientes=new(sync.Map)
    type canalesStruct struct{
        sender chan []byte
        close chan bool
    }
    func (broker *brokerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
    if !ok {
        http.Error(w, "Streaming unsupported!", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")
    var ID string
    //Get the ID somehow
    canales:=new(canalesStruct)
    canales.sender=make(chan []byte)
    canales.close=make(chan bool)
    clientes.store(ID,canales)
    notify := w.(http.CloseNotifier).CloseNotify()
    defer func() {
        clientes.Delete(ID)
    }()
    for {
         select {
            case <-notify:
                return
            case <-canales.close:
                return  
            case data:= <-canales.sender:
                fmt.Fprintf(w, "data: %s\n\n",data)
                flusher.Flush()
            }
      }
}

    func sendDataToChanelID(ID string,data []byte){
        canalesRaw,_:=clientes.Load(ID)
        canales,_:=canalRaw(*canalesStruct)
        canales.sender <-data
    }

So I have two question over there: 所以我在那边有两个问题:

  1. If connection drops WHILE is being receiving data, will fmt.Fprintf continue waiting endless or it will return immediately? 如果WHILE正在接收数据时连接断开,fmt.Fprintf会继续等待无休止,还是会立即返回?
  2. In case it returns immediately there is not problem, but in case it continues waiting how can I wrapp "fmt.Fprintf" in order to return if timeout exceed? 万一它立即返回没有问题,但万一它继续等待,如果超时超过了,我该如何包装“ fmt.Fprintf”以便返回呢?

A simple way to return different values depending on timing is to wait on a channel. 根据时序返回不同值的一种简单方法是在通道上等待。

func F() int {
    // channel to receive info
    c := make(chan int)
    // start timeout goroutine
    go func() {
        time.Sleep(TIMEOUT)
        c <- -1
    }()
    // start work goroutine
    go func() {
        c <- GetValue()
    }()
    // receive value
    x := <-c
    // start goroutine to discard late value
    go func() {
        _ = <-c
    }()
    // return received value
    return x
}

So, the two goroutines are racing each other. 因此,两个goroutine相互竞争。 If the timeout gets there first, the value is -1. 如果超时首先到达那里,则值为-1。

I beleive a call to fmt.Fprintf() will just fail when the underlying HTTP request closes. 我相信对fmt.Fprintf()的调用fmt.Fprintf()在基础HTTP请求关闭时失败。

"To fail" here means it will return a non-nil error. 这里的“失败”表示它将返回非空错误。

So, to properly handle the case of HTTP request being shut down, check the error return of fmt.Fprintf() , like in 因此,要正确处理HTTP请求被关闭的情况,请检查fmt.Fprintf()的错误返回,例如

_, err := fmt.Fprintf(w, ...)
if err != nil {
   // We have failed to write to the underlying connection
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM