2013-07-13 61 views
4

我正在嘗試爲多個處理程序設置一個http標頭。我的第一個想法是創建一個自定義寫入函數,在寫入響應之前設置標題,如底部的代碼示例。爲多個處理程序設置http標頭

但是,當我傳遞一個指向http.ResponseWriter的指針並嘗試從我的函數訪問它時,它告訴我「type * http.ResponseWriter沒有Header方法」。

什麼是爲多個處理程序設置標頭的最佳方式,以及爲什麼指針不按我想要的方式工作?

func HelloServer(w http.ResponseWriter, req *http.Request) { 
    type Message struct { 
     Name string 
     Body string 
     Time int64 
    } 

    m := Message{"Alice", "Hello", 1294706395881547000} 

    b, _ := json.Marshal(m) 
    WriteJSON(&w, b) 
} 

func WriteJSON(wr *http.ResponseWriter, rawJSON []byte) { 
    *wr.Header().Set("Content-Type", "application/json") 

    io.WriteString(*wr, string(rawJSON)) 
} 

func main() { 
    http.HandleFunc("/json", HelloServer) 

    err := http.ListenAndServe(":9000", nil) 
    if err != nil { 
    log.Fatal("ListenAndServer: ", err) 
    } 
} 

回答

4

我不確定多個處理程序的事情,但我知道你寫的代碼爲什麼失敗。關鍵是該行:

*wr.Header().Set("Content-Type", "application/json") 

被解釋,因爲操作者的優先級的,如:

*(wr.Header().Set("Content-Type", "application/json")) 

由於wr具有類型*http.ResponseWriter,這是一個指針和接口,而比接口本身,這是行不通的。我假設你知道這一點,這就是你爲什麼要做*wr。我假設你意味着對編譯器:

(*wr).Header().Set("Content-Type", "application/json") 

如果我沒有記錯的話,應該編譯和循規蹈矩。

+0

其實,你並不需要一個取消引用結構。進入自動插入解引用時neccessary。Downvoted因爲誤導。修復後將刪除downvote。 – fuz

+0

好的,這很公平。 – joshlf

+0

好的,它是固定的。 – joshlf

1

您不需要使用*wr,因爲它已經引用了一個指針。

wr.Header().Set("Content-Type", "application/json")應該足夠了。

如果你想設置的「全球」報頭爲每個請求,您可以創建一個滿足http.HandleFunc功能(go.auth has a good example),然後換你的處理程序,如下所示:

http.HandleFunc("/hello", Defaults(helloHandler))

而且看看net/http文檔,which has further examples

0

我用一個錯誤處理程序 包裝我的處理程序,它調用了我的AddSafeHeader函數。

我根據它http://golang.org/doc/articles/error_handling.html ,但它不使用ServeHTTP所以它適用於將Appstats:

http.Handle("/", appstats.NewHandler(util.ErrorHandler(rootHandler))) 

這裏:

package httputil 

import (
    "appengine" 
    "net/http" 
    "html/template" 
) 

func AddSafeHeaders(w http.ResponseWriter) { 
    w.Header().Set("X-Content-Type-Options", "nosniff") 
    w.Header().Set("X-XSS-Protection", "1; mode=block") 
    w.Header().Set("X-Frame-Options", "SAMEORIGIN") 
    w.Header().Set("Strict-Transport-Security", "max-age=2592000; includeSubDomains") 
} 

// Redirect to a fixed URL 
type redirectHandler struct { 
    url string 
    code int 
} 

func (rh *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
    Redirect(w, r, rh.url, rh.code) 
} 

func Redirect(w http.ResponseWriter, r *http.Request, urlStr string, code int) { 
    AddSafeHeaders(w) 
    http.Redirect(w, r, urlStr, code) 
} 

// RedirectHandler returns a request handler that redirects 
// each request it receives to the given url using the given 
// status code. 
func RedirectHandler(url string, code int) http.Handler { 
    return &redirectHandler{url, code} 
} 

func ErrorHandler(fn func(appengine.Context, http.ResponseWriter, *http.Request)) func(appengine.Context, http.ResponseWriter, *http.Request) { 
    return func(c appengine.Context, w http.ResponseWriter, r *http.Request) { 
    defer func() { 
     if err, ok := recover().(error); ok { 
     c.Errorf("%v", err) 
     w.WriteHeader(http.StatusInternalServerError) 
     errorTemplate.Execute(w, err) 
     } 
    }() 
    AddSafeHeaders(w) 
    fn(c, w, r) 
    } 
} 

// Check aborts the current execution if err is non-nil. 
func Check(err error) { 
    if err != nil { 
    panic(err) 
    } 
} 

var errorTemplate = template.Must(template.New("error").Parse(errorTemplateHTML)) 

const errorTemplateHTML = ` 
<html> 
<head> 
     <title>XXX</title> 
</head> 
<body> 
     <h2>An error occurred:</h2> 
     <p>{{.}}</p> 
</body> 
</html> 
` 
0

http.ResponseWriter是一個接口。

您應該不會使用指向接口的指針。在net/http/server.go中,未導出的response結構是當服務器調用處理程序時實現ResponseWriter的實際類型,重要的是,它通過*response。它的已經是的指針了,但是你沒有看到,因爲ResonseWriter是一個接口。 。(響應指針創建here,由(c *conn).readRequest(該鏈接可能是錯誤的線條未來,但你應該能夠找到他們)

這就是爲什麼實施Handler所需的ServeHTTP功能是:

ServeHTTP(w ResponseWriter, r *Request) 

即不是一個指向ResponseWriter,因爲這已經宣告允許指針到實現ResponseWriter接口。