如何处理多余的 response.WriteHeader 调用以返回 500

Ben*_*der 7 go

我知道http.ResponseWriterWriteHeader方法每个 HTTP 响应只能调用一次,只能有一个响应状态代码,并且只能发送一次标头。这一切都很好。

问题是,如果返回错误,我应该如何重构我的代码以覆盖201和返回?正如您在下面看到的,我故意强制恐慌以查看httprouter.Router.PanicHandler如何处理它。正如预期的那样,日志显示和响应是因为如上所述为时已晚。500http.ResponseWriter.Writehttp: superfluous response.WriteHeader call from ...201

package server

import (
    "github.com/julienschmidt/httprouter"
    "log"
    "net/http"
)

func Serve() {
    rtr := httprouter.New()
    rtr.GET("/", home.Welcome)

    handle500(rtr)

    err := http.ListenAndServe(":8080", rtr)
    if err != nil {
        log.Fatalf("server crash")
    }
}

func handle500(r *httprouter.Router) {
    r.PanicHandler = func(res http.ResponseWriter, req *http.Request, err interface{}) {
        res.WriteHeader(http.StatusInternalServerError)
        // http: superfluous response.WriteHeader call from line above
    }
}
Run Code Online (Sandbox Code Playgroud)
package home

import (
    "github.com/julienschmidt/httprouter"
    "net/http"
)

func Welcome(res http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
    // doing a few bits and building the body

    res.Header().Set("Content-Type", "application/json")
    res.WriteHeader(201)

    _, err := res.Write("body goes here")
    if err == nil {  // I am doing this deliberately to test 500
        panic("assume that something has gone wrong with res.Write and an error occurred")
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*oij 12

无法“覆盖”状态代码,因为它会立即发送到浏览器。

您正在检查 的返回值http.ResponseWriter.Write()。我不确定这是一个好策略。如果写入响应失败,那么写入更多也可能会失败。

记录失败似乎更合适,但我希望大多数失败是连接断开和其他不需要操作的错误。

  • 我发现这个答案是在寻找另一个问题。仅供参考 [至少从 Go 1.17 开始](https://cs.opensource.google/go/go/+/refs/tags/go1.17.1:src/net/http/server.go;l=120-126) ,“http.ResponseWriter.Write”隐式调用“w.WriteHeader(http.StatusOK)”,无论这是否是您想要的。因此,在将任何内容写入响应之前,您必须手动调用“w.WriteHeader”以手动设置 HTTP 代码。 (7认同)