记录对 http.HandleFunc 内传入 HTTP 请求的响应

2023-11-22

这是一个后续问题在go中,如何检查写入http.ResponseWriter的http响应?因为那里的解决方案需要伪造请求,这对于单元测试非常有用,但不适用于实时服务器。

我想将我的 Web 服务为响应从用户收到的请求而返回的 HTTP 响应转储到日志文件(或控制台)中。输出应该告诉我标头是什么以及 JSON 负载。

该怎么做呢?

如果有一个 httputil.DumpResponse 等效项将 http.ResponseWriter 作为参数而不是 http.Response ,那就完美了,但目前我只能从 http.ResponseWriter 访问标头

r = mux.NewRouter()
r.HandleFunc("/path", func (w http.ResponseWriter, r *http.Request) {

    fmt.Printf("r.HandleFunc /path\n")

    resp := server.NewResponse()
    defer resp.Close()

    r.ParseForm()

    // Server does some work here
    // ...

    // Insert debug code here, something like
    //
    // dump = http.DumpResponseFromWriter(w)
    // fmt.Printf("%s\n", dump)
});
http.Handle("/path", r)

中间件链接

该问题的常见解决方案是所谓的中间件链。有几个库提供此功能,例如negroni.

这是一种连续传递风格,您可以在其中编写中间件像这样的函数(取自 negroni 的自述文件):

func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  // do some stuff before
  next(rw, r)
  // do some stuff after
}

然后 negroni 为您提供一个 HTTP 处理程序,以正确的顺序调用您的中间件。

我们可以稍微不同地实现这个解决方案,使其变得不那么神奇但更实用(如函数式编程) 方法。定义处理程序组合器如下:

func NewFooHandler(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // do some stuff before
        next(r,w)
        // do some stuff after
    }
}

然后将您的链定义为组合:

h := NewFooHandler(NewBarHandler(NewBazHandler(Sink)))

Now h is an http.HandlerFunc依次执行 foo、bar、baz。Sink只是一个空的最后一个处理程序,它不执行任何操作(“完成”链。)

将此解决方案应用于您的问题

定义一个处理程序组合器:

func NewResponseLoggingHandler(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        // switch out response writer for a recorder
        // for all subsequent handlers
        c := httptest.NewRecorder()
        next(c, r)

        // copy everything from response recorder
        // to actual response writer
        for k, v := range c.HeaderMap {
            w.Header()[k] = v
        }
        w.WriteHeader(c.Code)
        c.Body.WriteTo(w)

    }
}

现在问题归结为处理程序管理。您可能希望将此处理程序应用于某个类别中的所有链。为此,您可以再次使用组合器(这在某种程度上相当于 negroni 的Classic()方法):

func NewDefaultHandler(next http.HandlerFunc) http.HandlerFunc {
    return NewResponseLoggingHandler(NewOtherStuffHandler(next))
}

此后,每当您启动这样的链时:

h := NewDefaultHandler(...)

它将自动包含响应日志记录和您在中定义的所有默认内容NewDefaultHandler.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

记录对 http.HandleFunc 内传入 HTTP 请求的响应 的相关文章

  • 无法将字符串解组为 int64 类型的 Go 值

    我有结构 type tySurvey struct Id int64 json id omitempty Name string json name omitempty I do json Marshal在 HTML 页面中写入 JSON
  • K8s更改配置映射并更新应用程序日志级别

    我想更改在 K8S 上运行的 Golang 应用程序的登录配置 我在本地尝试了以下代码 它按预期工作 我正在使用 viper 来监视配置文件更改 这是带有日志配置的配置图 apiVersion v1 kind ConfigMap data
  • 使用哪个 HTTP 状态代码来拒绝由于乐观锁定失败而导致的 PUT

    假设我想实现某种乐观锁定并使用 ETag 来指示最新的资源状态 这意味着 客户将使用If Match标题时PUT等待更新 根据HTTP规范 http www w3 org Protocols rfc2616 rfc2616 sec14 ht
  • 发送压缩文件 Spring

    我想通过我的 spring 控制器发送一个已经存在的压缩文件 但我不断收到这些错误消息org springframework web HttpMediaTypeNotAcceptableException Could not find ac
  • Node.JS Web 服务器中的安全性

    所以 我正在学习 Node JS 到目前为止我很喜欢它 我已经有几个项目在工作了 我想我可以在其中使用nodejs 不过 我担心安全问题 如果我使用 Node JS http 模块编写自定义 Web 服务器 我是否可能非常容易受到攻击 Ap
  • runtime.LockOSThread 是否允许子 goroutine 在同一个操作系统线程中运行?

    我明白在 Go 中 runtime LockOSThread https golang org pkg runtime LockOSThread将一个 goroutine 绑定到一个操作系统线程 并且不允许其他 goroutine 在该线程
  • 当 REST 中的资源不支持操作时,HTTP 状态代码 404 或 501

    我有一个 REST 服务 根据正在查看的资源类型 我有某些可用的操作 So Resource1支持Operation1 and Operation2 eg Resource1 Operation1 Resource1 Operation2
  • Golang、mysql:错误1040:连接过多

    我正在使用 github com go sql driver mysql 驱动程序 我打开一个数据库 db err sql Open mysql str 然后我有两个函数 每个函数被调用 200 次 并使用以下 mysql 代码 rows
  • 是否可以阻止在每个 HTTP 请求中发送 cookie?

    我最近发现 这里 每个网络请求都会发送浏览器cookie吗 https stackoverflow com questions 1336126 does every web request send the browser cookies
  • Bazel 构建缺少严格的依赖关系

    我正在尝试使用 brazel 构建 Go 应用程序 它是一个现有的私有 GitHub 存储库 位置如下 github xyz com repo name 我正在研究 我的目标是从 main go 文件创建一个二进制文件 该文件的方法依赖于其
  • 对于非文本媒体类型,发送带有 Content-Type 标头的字符集参数是否绝对错误?

    我发现了两个软件之间的错误 其中一个正在发出标头 Content Type application x bittorrent charset utf 8 另一个是错误地处理这个问题 但如果删除 charset 参数 则可以正确处理它 我需要
  • Go MSSQL 连接

    如何提供 MSSQL 连接 它说它始终与代码相关 即使信息不正确 也不会报错 package main import database sql fmt github com denisenkom go mssqldb log var ser
  • Golang Appengine 项目无法构建

    我有一个使用 golang 的应用程序引擎项目 我已经大约一年没有碰过了 我现在无法让它在之前构建的机器上构建 我收到以下错误 go app builder 解析输入失败 解析器 src golang org x net internal
  • 我首次设置 AWS EB 时创建的默认安全组是什么?

    我对几个组所扮演的角色感到困惑 这些组似乎已自动添加到我的 AWS 安全组列表中 并以我收集的默认配置进行连接 并且想知道它们是如何工作的 以及它们的安全性如何 改变 具体来说 有三个神秘之处 launch wizard 1其中有一条入站规
  • GET 和 POST 方法的单独 Flask 路由

    在 Flask 中定义路由时 最好的做法是使用由多个 HTTP 方法定义的单个路由 并在该单个路由中使用显式逻辑处理不同的 HTTP 方法 例如 app route api users methods GET POST def users
  • HTTP请求压缩

    一般用例 想象一下一个正在上传大量 JSON 的客户端 内容类型应保留application json因为这描述了实际数据 Accept Encoding 和 Transfer Encoding 似乎是为了告诉服务器应该如何格式化响应 看起
  • “双点”可以作为 URL 路径部分的一部分吗

    在 URL 中使用父目录双点是否有效且安全 如下例所示 http example com path to file jpg RFC3986 https www rfc editor org rfc rfc3986定义 URI 它描述了路径如
  • 如何在 Goji (Golang) 中使用不同的中间件创建单独的路由组?

    我正在使用Goji https github com zenazn goji https github com zenazn goji 并希望定义具有自己的中间件的路由组 例如 下面的所有路径 company应使用 LDAP 身份验证并定义
  • 给定方法值,获取接收者对象

    Go 有没有办法从方法值获取接收者对象 例如有没有这样的MagicFunc这将使以下程序输出字符串my info来自底层 Foo 实例 package main import fmt type Foo struct A string fun
  • 共享来自单独命令/进程的属性

    我提供带有多个命令和子命令的命令行工具 我使用cobra https github com spf13 cobra命令行 我有两个单独的命令首先是前提条件e 给其他人 例如第一个命令是通过创建临时文件夹并验证某些文件来首选环境 第二个命令应

随机推荐