You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Golang ServeHTTP记录响应状态码时遇空指针引用错误

问题分析

错误invalid memory address or nil pointer dereference是因为你尝试访问req.Response.StatusCode,但服务端处理的*http.Request对象里,Response字段是nil——这个字段只有客户端发起请求(比如用http.Client)时才会被填充,服务端接收的请求里根本没有这个值,直接访问必然触发空指针 panic。

解决方案:自定义ResponseWriter记录状态码

要获取响应状态码,你得自己包装http.ResponseWriter,在写入响应时记录状态码,具体步骤如下:

  1. 定义嵌入http.ResponseWriter的自定义结构体,用来记录状态码:
type ResponseRecorder struct {
    http.ResponseWriter
    statusCode int
}

func NewResponseRecorder(w http.ResponseWriter) *ResponseRecorder {
    // 默认状态码设为200,因为未显式调用WriteHeader时,响应默认状态就是200
    return &ResponseRecorder{w, http.StatusOK}
}

// 重写WriteHeader,记录状态码
func (rr *ResponseRecorder) WriteHeader(code int) {
    rr.statusCode = code
    rr.ResponseWriter.WriteHeader(code)
}

// 处理直接调用Write但未调用WriteHeader的情况,确保状态码正确
func (rr *ResponseRecorder) Write(b []byte) (int, error) {
    if rr.statusCode == 0 {
        rr.statusCode = http.StatusOK
    }
    return rr.ResponseWriter.Write(b)
}
  1. 修改ServeHTTP函数,用自定义的ResponseRecorder包装原w,日志记录时用记录的状态码:
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    handler := r.getHandler(req.Method, req.URL.Path)
    if handler == nil {
        notFoundHandler(w, req)
        return
    }

    // 用自定义ResponseRecorder包装原响应写入器
    rr := NewResponseRecorder(w)
    reqStruct := newReqStruct(rr, req) // 确保newReqStruct兼容http.ResponseWriter接口即可

    // 这里的goroutine完全多余——启动后立刻阻塞等待done,和同步调用没区别,直接去掉简化代码
    handler(reqStruct)
    
    // 用记录的状态码打日志
    logger.logRequest(req.URL.Path, req.Method, rr.statusCode)
}
额外注意
  • 确认newReqStruct的参数是http.ResponseWriter接口类型,这样自定义的ResponseRecorder可以直接传入,因为它实现了该接口。
  • 原代码里的goroutine和chan属于冗余代码,完全可以删除,不会影响功能,还能减少不必要的并发开销。

内容的提问来源于stack exchange,提问作者Folium

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 18:42:47