jjzjj

http - 在 http.HandleFunc 中记录对传入 HTTP 请求的响应

coder 2023-06-26 原文

这是 In go, how to inspect the http response that is written to http.ResponseWriter? 的后续问题因为那里的解决方案需要伪造一个请求,这对于单元测试非常有用,但不适用于实时服务器。

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

如何做到这一点?

如果有一个 httputil.DumpResponse 等价物将 http.ResponseWriter 而不是 http.Response 作为参数,那将是完美的,但目前我只能从 http.ResponseWriter 访问 Header

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)))

现在 h 是一个 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 中定义的所有默认内容。

关于http - 在 http.HandleFunc 中记录对传入 HTTP 请求的响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29319783/

有关http - 在 http.HandleFunc 中记录对传入 HTTP 请求的响应的更多相关文章

  1. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  4. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  5. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  6. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  7. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  8. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  9. ruby-on-rails - 事件记录 : Select max of limit - 2

    我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).

  10. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

    Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

随机推荐