首页 > 解决方案 > 当请求被取消或超时时如何从 http 处理程序返回

问题描述

我在做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
    }

所以我有两个问题:

  1. 如果在接收数据时连接断开,fmt.Fprintf 会继续无限等待还是会立即返回?
  2. 如果它立即返回没有问题,但如果它继续等待,我该如何包装“fmt.Fprintf”以便在超时超过时返回?

标签: gotimeouteventsource

解决方案


根据时间返回不同值的一种简单方法是在通道上等待。

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
}

因此,这两个 goroutine 正在相互竞争。如果超时首先到达那里,则值为 -1。


推荐阅读