【问题标题】:Superfluous WriteHeader and no response [closed]多余的 WriteHeader 并且没有响应 [关闭]
【发布时间】:2021-03-18 02:56:59
【问题描述】:

我正在编写一个向 WebSocket 网关发送请求的 HTTP API。我正在使用go1.14.7gorilla/mux v1.8.0。代码将使用GOOS=linuxGOARCH=armGOARM=7进行交叉编译。

我的问题如下:

  • respondBadRequest() 总是记录这个,即使我从不使用 WriteHeader
    • http: superfluous response.WriteHeader call from main.(*HttpHandler).respondBadRequest
  • API 响应始终为 200 OK,即使在调用 respondBadRequest() 时也是如此
  • API 响应的正文始终为空

我对 Go 完全陌生。下面是我的代码结构。

type HttpHandler struct {
  gateway Gateway
}

func (h *HttpHandler) respondSuccess(w http.ResponseWriter, text string) {
  w.Write([]byte(text))
}

func (h *HttpHandler) respondBadRequest(w http.ResponseWriter, text string) {
  http.Error(w, text, http.StatusBadRequest)
}

func (h *HttpHandler) respondError(w http.ResponseWriter, text string) {
  http.Error(w, text, http.StatusInternalServerError)
}

func (h *HttpHandler) OnFoobar(w http.ResponseWriter, r *http.Request) {
  f := func(success bool, e error) {
    if e != nil {
      h.respondError(w, e.Error())
    } else if success {
      h.respondSuccess(w, "Foobar Accepted")
    } else {
      h.respondBadRequest(w, "Unknown Foobar")
    }
  }
  //...
  e := h.gateway.Foobar(f)
  if e != nil {
    log.Println(e)
  }
}

//...

httpHandler := &HttpHandler{
  gateway: gateway,
}

r := mux.NewRouter()

r.HandleFunc("/foobar", httpHandler.OnFoobar)

http.ListenAndServe(":8000", r)

【问题讨论】:

  • 如果你写了响应的任何部分,WriteHeader 已经被调用了。写完响应后,不能再发送不同的标头。
  • 您不是直接调用WriteHeader,而是在多个地方间接调用它;如果您调用Write 并且WriteHeader 尚未被调用,Write 将调用WriteHeader(200)(如文档中所述)。 http.Error 也调用 WriteHeader。如果您想以错误响应,您必须在调用Write 发送任何正文内容之前 这样做(在HTTP 响应中,状态和标头必须 在响应正文)。
  • f 看起来像一个回调,所以我猜Foobar 是异步的?它是在 goroutine 中完成它的工作吗?如果是这样,处理程序OnFoobar 不会等待Foobar 完成并且当它退出时,如果尚未写入w,则Go 的服务多路复用器将默认写入200ok,然后稍后当Foobar完成,它会调用你得到错误的回调。
  • @Steffen 在这种情况下使用sync.WaitGroup
  • @Steffen 应该这样做,我相信:play.golang.org/p/_2DkCVXmhcS

标签: go gorilla go-http


【解决方案1】:

正如@mkopriva 指出的f 显然是在OnFoobar 已经完成并写了一个隐含的空响应之后调用的。他使用sync.WaitGroup修复:

func (h *HttpHandler) OnFoobar(w http.ResponseWriter, r *http.Request) {
  wg := new(sync.WaitGroup)
  wg.Add(1)
  f := func(success bool, e error) {
    if e != nil {
      h.respondError(w, e.Error())
    } else if success {
      h.respondSuccess(w, "Foobar Accepted")
    } else {
      h.respondBadRequest(w, "Unknown Foobar")
    }
    wg.Done()
  }
  //...
  e := h.gateway.Foobar(f)
  if e != nil {
    log.Println(e)
  }
  wg.Wait()
}

【讨论】:

    猜你喜欢
    • 2017-03-28
    • 1970-01-01
    • 1970-01-01
    • 2014-07-21
    • 1970-01-01
    • 2020-05-08
    • 1970-01-01
    • 2021-05-23
    相关资源
    最近更新 更多