Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HTTPステータスコードが意図した値にならないとき Let's Go Talk #2

aboy
August 03, 2022

HTTPステータスコードが意図した値にならないとき Let's Go Talk #2

Let's Go Talk #2でLTした資料です。

aboy

August 03, 2022
Tweet

More Decks by aboy

Other Decks in Programming

Transcript

  1. 例えばこんなコード type MyHandler struct{} func (h *MyHandler) Sample(w http.ResponseWriter, r

    *http.Request) { w.Write([]byte("sample")) w.WriteHeader(http.StatusTeapot) } func Test(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", nil) res := httptest.NewRecorder() h := &MyHandler{} h.Sample(res, req) if res.Code != http.StatusTeapot { t.Errorf("status code got %d, should be %d", res.Code, http.StatusTeapot) } } === RUN Test main_test.go:40: status code got 200, should be 418 --- FAIL: Test (0.00s)
  2. http.ResponseWriterに何かありそうだ type MyHandler struct{} func (h *MyHandler) Sample(w http.ResponseWriter, r

    *http.Request) { w.Write([]byte("sample")) w.WriteHeader(http.StatusTeapot) } func Test(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/", nil) res := httptest.NewRecorder() h := &MyHandler{} h.Sample(res, req) if res.Code != http.StatusTeapot { t.Errorf("status code got %d, should be %d", res.Code, http.StatusTeapot) } } === RUN Test main_test.go:40: status code got 200, should be 418 --- FAIL: Test (0.00s)
  3. WriteHeader() - rw.wroteHeaderなら何もせずreturn // WriteHeader implements http.ResponseWriter. func (rw *ResponseRecorder)

    WriteHeader(code int) { if rw.wroteHeader { return } checkWriteHeaderCode(code) rw.Code = code rw.wroteHeader = true if rw.HeaderMap == nil { rw.HeaderMap = make(http.Header) } rw.snapHeader = rw.HeaderMap.Clone() }
  4. WriteHeader() - rw.wroteHeaderに値を代入しているのはWriteHeader()内のみ // WriteHeader implements http.ResponseWriter. func (rw *ResponseRecorder)

    WriteHeader(code int) { if rw.wroteHeader { return } checkWriteHeaderCode(code) rw.Code = code rw.wroteHeader = true if rw.HeaderMap == nil { rw.HeaderMap = make(http.Header) } rw.snapHeader = rw.HeaderMap.Clone() }
  5. WriteHeader() - つまりWriteHeader()では、ResponseRecorderのインスタンスは一度だけ HTTPステータスコードを設定できる // WriteHeader implements http.ResponseWriter. func (rw

    *ResponseRecorder) WriteHeader(code int) { if rw.wroteHeader { return } checkWriteHeaderCode(code) rw.Code = code rw.wroteHeader = true if rw.HeaderMap == nil { rw.HeaderMap = make(http.Header) } rw.snapHeader = rw.HeaderMap.Clone() }
  6. Write() - 1行目でrw.writeHeader()という非公開メソッドを呼んでいるのでそいつを 見にいく // Write implements http.ResponseWriter. The data

    in buf is written to // rw.Body, if not nil. func (rw *ResponseRecorder) Write(buf []byte) (int, error) { rw.writeHeader(buf, "") if rw.Body != nil { rw.Body.Write(buf) } return len(buf), nil }
  7. writeHeader() - 色々あるけど今回の目的に沿って読むなら気になる箇所が2つ func (rw *ResponseRecorder) writeHeader(b []byte, str string)

    { if rw.wroteHeader { return } if len(str) > 512 { str = str[:512] } m := rw.Header() _, hasType := m["Content-Type"] hasTE := m.Get("Transfer-Encoding") != "" if !hasType && !hasTE { if b == nil { b = []byte(str) } m.Set("Content-Type", http.DetectContentType(b)) } rw.WriteHeader(200) }
  8. writeHeader() - WriteHeader()と同様に、wroteHeaderなら何もせずreturn func (rw *ResponseRecorder) writeHeader(b []byte, str string)

    { if rw.wroteHeader { return } if len(str) > 512 { str = str[:512] } m := rw.Header() _, hasType := m["Content-Type"] hasTE := m.Get("Transfer-Encoding") != "" if !hasType && !hasTE { if b == nil { b = []byte(str) } m.Set("Content-Type", http.DetectContentType(b)) } rw.WriteHeader(200) }
  9. writeHeader() - 処理の最後にWriteHeader(200)を呼び出している func (rw *ResponseRecorder) writeHeader(b []byte, str string)

    { if rw.wroteHeader { return } if len(str) > 512 { str = str[:512] } m := rw.Header() _, hasType := m["Content-Type"] hasTE := m.Get("Transfer-Encoding") != "" if !hasType && !hasTE { if b == nil { b = []byte(str) } m.Set("Content-Type", http.DetectContentType(b)) } rw.WriteHeader(200) }
  10. writeHeader() - つまりWrite()は(body書き込み前に)HTTPステータスコード200を設定する func (rw *ResponseRecorder) writeHeader(b []byte, str string)

    { if rw.wroteHeader { return } if len(str) > 512 { str = str[:512] } m := rw.Header() _, hasType := m["Content-Type"] hasTE := m.Get("Transfer-Encoding") != "" if !hasType && !hasTE { if b == nil { b = []byte(str) } m.Set("Content-Type", http.DetectContentType(b)) } rw.WriteHeader(200) }