登录
首页 >  Golang >  Go问答

在中间件中无法追踪 HTTP 响应代码

来源:stackoverflow

时间:2024-02-14 19:48:24 388浏览 收藏

本篇文章主要是结合我之前面试的各种经历和实战开发中遇到的问题解决经验整理的,希望这篇《在中间件中无法追踪 HTTP 响应代码》对你有很大帮助!欢迎收藏,分享给更多的需要的朋友学习~

问题内容

我正在使用 go-openapi 从 swagger 配置生成一个 http 服务器并处理所有处理程序。 我的中间件的架构是 request -> override func -> do http stuff -> 日志响应代码 -> response

这是我的中间件:

func (pm *prometheusmetrics) httpmiddleware(h http.handler) http.handler {
    return http.handlerfunc(func(w http.responsewriter, r *http.request) {
        start := time.now()
        statusrecoder := &utils.statusrecorder{responsewriter: w, statuscode: 200}
        logrus.infof("--> %v %v", r.method, r.url.path)
        // statusrecoder := negroni.newresponsewriter(w) <-- tried this solution, didn't worked

        h.servehttp(statusrecoder, r)

        logrus.infof("<-- %v", statusrecoder.status()) // should display status code
        duration := time.since(start)
        statuscode := strconv.itoa(statusrecoder.status())

        pm.pushhttpmetrics(r.url.path, statuscode, duration.seconds())
    })
}

这是我传递中间件的方式:

func setupglobalmiddleware(handler http.handler, prommetrics *apihandlers.prometheusmetrics) http.handler {
    middle := interpose.new()
    middle.usehandler(handler)

    recoverymiddleware := recovr.new()
    middle.use(recoverymiddleware)

    logrusmiddleware := interposemiddleware.negronilogrus()
    middle.use(logrusmiddleware)
    middle.use(func(h http.handler) http.handler {
        return prommetrics.httpmiddleware(h)
    })

    corsmiddleware := cors.new(cors.options{
        allowedheaders:     []string{"*"},
        allowedorigins:     []string{"*"},
        allowedmethods:     []string{"get", "post", "put", "patch", "delete", "options"},
        maxage:             1000,
        optionspassthrough: false,
    })
    if log.getlevel() >= log.debuglevel {
        corsmiddleware.log = log.standardlogger()
    }

    return corsmiddleware.handler(middle)
}

最后,我调用 setupglobalmiddleware 函数:

func configureapi(api *operations.kubeesapi) http.handler { // operations is package generated by go-openapi
    // some setup...
    return setupglobalmiddleware(api.serve(setupmiddlewares), prommetrics)
}

statusrecoder 的重写:

type StatusRecorder struct {
    http.ResponseWriter
    StatusCode int
}

// WriteHeader is the fake function to record status code
func (rec *StatusRecorder) WriteHeader(statusCode int) {
    logrus.Infof("hello there: %v", statusCode)
    rec.StatusCode = statusCode
    rec.ResponseWriter.WriteHeader(statusCode)
}

如您所见,我重写了 http.handler 中的 writeheader 函数,以仅存储状态代码并在外部访问它,然后调用原始 writeheader 函数。这里的问题是我的函数 writeheader 从未被调用。并且无法弄清楚为什么不是。


解决方案


如果您没有完整的软件包列表,那么答案会更难理解。
问题在于 go-openapigo-swagger 在代码中实现中间件并处理它们的方式。许多其他已安装的软件包也存在此问题。
为了确保正确检索状态代码,我将中间件放在中间件声明的右底部。

代码:

func setupglobalmiddleware(handler http.handler, prommetrics *apihandlers.prometheusmetrics) http.handler {
    middle := interpose.new()
    middle.usehandler(handler)

    recoverymiddleware := recovr.new()
    middle.use(recoverymiddleware)

    logrusmiddleware := interposemiddleware.negronilogrus()
    middle.use(logrusmiddleware)

    // the old declaration was here

    corsmiddleware := cors.new(cors.options{
        allowedheaders:     []string{"*"},
        allowedorigins:     []string{"*"},
        allowedmethods:     []string{"get", "post", "put", "patch", "delete", "options"},
        maxage:             1000,
        optionspassthrough: false,
    })
    if log.getlevel() >= log.debuglevel {
        corsmiddleware.log = log.standardlogger()
    }

    // notice the changement where the prommetrics.httpmiddleware is now in the bottom
    return corsmiddleware.handler(prommetrics.httpmiddleware(middle))
    // return corsmiddleware.handler(middle) <-- old line
}

因为go使用组合,而不是继承。 writeheader 最常在第一次调用 write() 时自动调用。来自http.ResponseWriter documentation

但由于您尚未定义自己的 write 方法,因此将调用嵌入式方法(由 http.responsewriter 的嵌入式实例提供)。当调用 write() 方法,然后调用 writeheader 时,它会调用原始 writeheader 方法,而不是您的版本。

解决方案是还提供您自己的 write 方法,该方法包装原始方法,并在需要时调用您的 writeheader 版本。

type StatusRecorder struct {
    http.ResponseWriter
    StatusCode int
    written bool
}

// WriteHeader is the fake function to record status code
func (rec *StatusRecorder) WriteHeader(statusCode int) {
    rec.written = true
    logrus.Infof("hello there: %v", statusCode)
    rec.StatusCode = statusCode
    rec.ResponseWriter.WriteHeader(statusCode)
}

func (rec *StatusRecorder) Write(p []byte) (int, error) {method
    if !rec.written {
        rec.WriteHeader(http.StatusOK)
    }
    return rec.Write(p)
}

以上就是《在中间件中无法追踪 HTTP 响应代码》的详细内容,更多关于的资料请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>