【问题标题】:http override http header code in golang while there is an error in json encodinghttp覆盖golang中的http头代码,而json编码有错误
【发布时间】:2018-09-04 02:31:14
【问题描述】:

考虑一下这种情况!

http请求执行成功后,如果执行json编码出错,如何覆盖header代码

func writeResp(w http.ResponseWriter, code int, data interface{}) {
    w.Header().Set("Content-Type", "application/json")

    //Here I set the status to 201 StatusCreated
    w.WriteHeader(code) 
    s := success{Data: data}

    //what if there is an error here and want to override the status to 5xx error
    //how to handle error here, panic?, http.Error() is not an option because as we already wrote header to 201, it just prints `http: multiple response.WriteHeader calls`
    if err := json.NewEncoder(w).Encode(s); err != nil {
        w.Header().Set("Content-Type", "application/json")

        //it throws http: multiple response.WriteHeader calls here as we already wrote header above to 201
        w.WriteHeader(code)
        e := errorResponse{
            Code:        code,
            Error:       error,
            Description: msg,
        }
        if err := json.NewEncoder(w).Encode(e); err != nil {
         //same how to handle here
        }
    }
}

我在这里有多个选项,如果我们只是进行致命日志记录,用户将不会确切知道发生了什么,即使我使用w.Write([]byte(msg)) 编写字符串,状态仍然显示201 created,如何以错误代码 5xx 响应

非常感谢任何帮助

【问题讨论】:

  • 必须 调用 WriteHeader,直到您知道要返回什么状态代码。 绝对 没有 方法可以在调用 WriteHeader 后更改该状态。
  • 但是 json.NewEncoder(w).Encode(e) 如果 WriteHeader 没有被显式调用,那么在内部进行写入的 json.NewEncoder(w).Encode(e) 会将状态设置为 StatusOK,这不是我需要的,我想将其设置为 StatusCreated
  • 阅读文档。仅当您自己没有 WriteHeader 时,内部写入将设置为 200,一旦您知道要发送哪个状态代码,您应该这样做。真的很简单。
  • 阅读评论,您所描述的正是我在之前的评论json.NewEncoder(w).Encode(e) which does a Write internally sets the status to StatusOK if WriteHeader is not called explicitly 中所写的内容,假设json.NewEncoder(w).Encode(e) 出现故障,我想设置状态码201 以表示成功和5xx 编码失败,你会怎么做?
  • 不要使用 json.Encoder。使用 json.Marshal。这真的很简单。或者写入中间缓冲区。

标签: http go error-handling net-http


【解决方案1】:

首先,编码时出错的可能性似乎不大。

查看此问题了解Marshal 失败的原因:

What input will cause golang's json.Marshal to return an error?

另一个潜在的错误原因是实际将数据写入响应流时出现问题,但在这种情况下,您也无法写入自定义错误。

回到你的问题,如果你担心编码你的对象可能会失败,你可以先编组你的数据(检查错误),然后如果编组成功,只写 201 状态代码(和编码的数据)。

稍微修改一下你的例子:

s := success{Data: data}
jsonData, err := json.Marshal(s)
if err != nil {
    // write your error to w, then return
}
w.WriteHeader(code)
w.Header().Set("Content-Type", "application/json")
w.Write(jsonData)

现在,最后一个 write 也可能引发错误。

但如果发生这种情况,在编写自定义错误时也会失败,因此在这种情况下,您最好将其记录在服务器端(或将该错误发送到 New Relic 等跟踪器)。

【讨论】:

  • 感谢您的回答,这是我目前正在关注的选项,有趣的问题是w.Write(Write([]byte) (int, error))返回错误,如何处理?
  • @JagadeeshVenkata:是的,好吧,如果您在那里收到错误,我认为您无法使用 http 响应通知用户(因为编写自定义错误响应也可能会失败)。您需要诉诸服务器端日志记录并监控这些日志。更新我的答案以添加最后一部分。
  • 这个答案不可能是正确的:在调用WriteHeader() 后更改标题映射没有效果,根据pkg.go.dev/net/http@go1.17.1#ResponseWriter
猜你喜欢
  • 2014-10-12
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 2019-07-11
相关资源
最近更新 更多