如果标题已设置,如何使用自定义http处理程序/中间件?

时间:2014-12-22 23:28:19

标签: go http-headers gorilla

我正在尝试将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。我看不到任何错误,除非我忘了在某个地方找到一个错误,但浏览器得到的回复无效。

有没有任何优雅的方法来解决这个问题,只是在某处隐藏标题然后离开最后的处理程序来编写它们?这似乎意味着重写处理程序的代码,如果可能的话,我很想避免。

2 个答案:

答案 0 :(得分:2)

拨打w.WriteHeader(404)后,标题即可开通。所以你不能再添加它了。 您可以做的最好的方法是缓冲状态代码并将其写在链的末尾。

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

答案 1 :(得分:1)

我经历了同样的默默失败行为。但只有在我使用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)