4

複数のハンドラーに http ヘッダーを設定しようとしています。私が最初に考えたのは、下部のコード サンプルのように、応答を書き込む前にヘッダーを設定するカスタム書き込み関数を作成することでした。

ただし、ポインタを http.ResponseWriter に渡して関数からアクセスしようとすると、「type *http.ResponseWriter has no Header method」と表示されます。

複数のハンドラーのヘッダーを設定する最良の方法は何ですか? また、ポインターが思いどおりに動作しないのはなぜですか?

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

6 に答える 6

4

複数のハンドラーについてはよくわかりませんが、あなたが書いたコードが失敗する理由はわかっています。重要なのは、次の行です。

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

演算子の優先順位により、次のように解釈されます。

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

インターフェイス自体ではなく、インターフェイスのポインタであるwrtype を持っているため、これは機能しません。あなたはそれを知っていたと思います。あなたがコンパイラに暗示するつもりだったのは次のとおりだと思います:*http.ResponseWriter*wr

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

私が間違っていなければ、コンパイルして正しく動作するはずです。

于 2013-07-13T22:21:51.167 に答える
3

*wr既にポインターを参照しているため、使用する必要はありません。

wr.Header().Set("Content-Type", "application/json")十分なはずです。

すべてのリクエストに「グローバル」ヘッダーを設定したい場合は、満たす関数を作成しhttp.HandleFunc( go.auth に良い例があります)、ハンドラーを次のようにラップします。

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

また、net/httpドキュメントを参照してください。これには、さらに例があります。

于 2013-07-14T05:47:08.980 に答える
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>
`
于 2013-07-16T00:31:19.553 に答える
0

http.ResponseWriterインターフェースです。

おそらく、インターフェイスへのポインターを使用するべきではありません。net/http/server.go では、エクスポートされていない構造体は、サーバーがハンドラーを呼び出すときにresponse実装される実際の型であり、重要なことに、サーバーが実際にハンドラーの ServeHTTPを呼び出すときに、. それはすでにポインターですが、インターフェイスであるため、それはわかりません。(応答ポインタは、 (c *conn).readRequestによってここに作成されます。(リンクは将来間違った行にリンクされる可能性がありますが、それらを見つけることができるはずです)。ResponseWriter*responseResonseWriter

そのため、ServeHTTP実装に必要な関数Handlerは次のとおりです。

ServeHTTP(w ResponseWriter, r *Request)

つまり、 へのポインターではありません。ResponseWriterこの宣言は、ResponseWriterインターフェイスを実装する構造体へのポインターを既に許可しているためです。

于 2016-10-08T01:03:06.903 に答える
0

私がやっていること:

// Accepts a user supplied http.HandlerFunc and then modifies it in various ways. In this case, it adds two new headers.
func CommonlHandler(h http.HandlerFunc) http.HandlerFunc {
    return func (rs http.ResponseWriter, rq *http.Request) {
        rs.Header().Add("Server", "Some server")
        rs.Header().Add("Cache-Control", "no-store")
        h(rs, rq)
}

// somewhere down the line, where you're setting up http request handlers

serveMux := http.NewServeMux()

serveMux.HandleFunc("/", CommonHandler(func(rs http.ResponseWriter, rq *http.Request) {
    // Handle request as usual. Since it's wrapped in the CommonHandler and we've set some headers there, responses to requests to "/" will contain those headers.
    // Be mindful what modifications you're doing here. If, for ex., you decide you want to apply different caching strategy than the Common one, since this will be passed to the CommonHandler, your changes will be overwritten and lost. So it may be a good idea to introduce checks in CommonHandler to determine whether the header exists, before you decide to create it.
}))

serveMux.HandleFunc("/contact", CommonHandler(func(rs http.ResponseWriter, rq *http.Request) {
    // handle another request as usual
}))
于 2020-07-16T20:23:25.450 に答える