【问题标题】:How to use custom http handlers/middleware if headers already set?如果已设置标头,如何使用自定义 http 处理程序/中间件?
【发布时间】:2015-05-28 17:07:08
【问题描述】:

我正在尝试在 go 中链接 HTTP 处理程序以提供一些附加功能,如下所示:

package router

import (
    // snip
    "github.com/gorilla/mux"
    "github.com/gorilla/handlers"
    "net/http"
)

// snip

r := mux.NewRouter()
/* routing code */
var h http.Handler
h = r
if useGzip {
    h = handlers.CompressHandler(h)
}
if useLogFile {
    fn := pathToLog
    accessLog, err := os.OpenFile(fn, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
    if err != nil {
        panic(err)
    }
    h = handlers.CombinedLoggingHandler(accessLog, h)
}

// etc...

问题是,如果 gorilla/mux 路由器指向的控制器之一已经设置了任何 HTTP 标头(例如,w.WriteHeader(404)w.Header().Set("Content-Type", "application/json")) - 这会默默地破坏任何试图设置或添加自己的标题,如compress handler。我看不到任何错误,除非我忘记在某个地方捕获一个错误,但浏览器得到一个无效响应。

是否有任何优雅的方法来处理这个问题,而不是将标题存储在某个地方,然后让最终的处理程序来编写它们?这似乎意味着重写处理程序的代码,如果可能的话,我很想避免这种情况。

【问题讨论】:

    标签: go http-headers gorilla


    【解决方案1】:

    一旦您调用w.WriteHeader(404),标头就会连接到电线上。所以你不能再添加它了。 您可以做的最好的方法是缓冲状态代码并将其写入链的末尾。

    例如,您可以为 http.ResponseWriter 提供自己的包装器,该包装器将重新实现 WriteHeader() 以保存状态值。然后添加方法Commit() 来实际编写它。 在最后一个处理程序中调用Commit()。当然,您必须以某种方式确定最后一个处理程序。

    【讨论】:

      【解决方案2】:

      我经历了同样的失败行为。但仅在我执行 WritheHeader 以设置 StatusOK 以外的状态代码的处理程序中。我认为 CompressHandler 的这一部分出了点问题:

      if h.Get("Content-Type") == "" {
          h.Set("Content-Type", http.DetectContentType(b))
      }
      

      在我自己的处理程序中明确设置内容类型时似乎已解决:

      w.Header().Set("Content-Type", "text/html; charset=utf-8")
      w.WriteHeader(code)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-03
        • 1970-01-01
        • 1970-01-01
        • 2016-01-04
        • 1970-01-01
        • 1970-01-01
        • 2011-04-09
        • 2012-10-25
        相关资源
        最近更新 更多