Go middleware取得handler回應內容如HTTP狀態碼(HTTP Status Code)、回應頭(Response Header)、回應主體(Response Body)的方式如下。
如果要取得handler中http.ResponseWriter
回應內容,可透過自訂一個實作http.ResponseWriter
介面的struct包裹原本的http.ResponseWriter
實例並在覆寫的方法中紀錄回應內容於欄位中。
範例環境:
- Go 1.18
範例
下面建立一個ResponseWriterRecord
struct繼承http.ResponseWriter
介面,欄位StatusCode
紀錄回應狀態碼;Body
紀錄回應主體,嵌入欄位為原本的http.ResponseWriter
。
繼承http.ResponseWriter
介面必須實作以下方法:
Header() Header
- 取得Response Header。直接調用原本的http.ResponseWriter.Header
。Write([]byte) (int, error)
- 寫出Response Body。寫出時將內容存在Body
欄位後再透過原本的http.ResponseWriter.Write
寫出內容。WriteHeader(statusCode int)
- 寫出HTTP回應狀態碼。寫出時將狀態碼存在StatusCode
欄位後再透過原本的http.ResponseWriter.WriteHeader
寫出狀態碼。
在middleware ResponseRecordHandlerFunc
中將原本的http.ResponseWriter
替換為ResponseWriterRecord
傳入下一個handler,所以傳入HellohandlerFunc
的http.ResponseWriter
實為ResponseWriterRecord
。
main.go
package main
import (
"encoding/json"
"log"
"net/http"
)
type ResponseWriterRecord struct {
StatusCode int
Body []byte
http.ResponseWriter
}
func NewResponseWriterRecord(w http.ResponseWriter) *ResponseWriterRecord {
return &ResponseWriterRecord{ResponseWriter: w}
}
func (r *ResponseWriterRecord) Header() http.Header {
return r.ResponseWriter.Header()
}
func (r *ResponseWriterRecord) Write(b []byte) (int, error) {
r.Body = b
return r.ResponseWriter.Write(b)
}
func (r *ResponseWriterRecord) WriteHeader(statusCode int) {
r.StatusCode = statusCode
r.ResponseWriter.WriteHeader(statusCode)
}
func ResponseRecordHandlerFunc(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var rw *ResponseWriterRecord = NewResponseWriterRecord(w)
h.ServeHTTP(rw, r)
if rw.StatusCode == 0 {
rw.StatusCode = http.StatusOK
}
header, err := json.Marshal(rw.Header())
if err != nil {
panic(err)
}
log.Printf("response status code=%d\nheader=%s\nbody=%s",
rw.StatusCode, string(header), string(rw.Body))
}
}
func main() {
http.HandleFunc("/hello", HellohandlerFunc())
http.HandleFunc("/hi", HiHandlerFunc())
handler := ResponseRecordHandlerFunc(http.DefaultServeMux)
http.ListenAndServe(":8080", handler)
}
func HellohandlerFunc() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write([]byte("hello"))
}
}
func HiHandlerFunc() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/plain")
w.WriteHeader(http.StatusAccepted)
w.Write([]byte("hi"))
}
}
測試
啟動專案並在命令列以curl執行curl -X GET "http://localhost:8080/hello" -i
返回如下。
$ curl -X GET "http://localhost:8080/hello" -i
HTTP/1.1 200 OK
Content-Type: text/plain
Date: Sat, 02 Jul 2022 15:52:46 GMT
Content-Length: 5
hello
在console印出以下日誌。
022/07/02 23:54:42 response status code=200, header={"Content-Type":["text/plain"]}, body=hello
接著在命令列以curl執行curl -X GET "http://localhost:8080/hi" -i
返回如下。
$ curl -X GET "http://localhost:8080/hi" -i
HTTP/1.1 202 Accepted
Content-Type: text/plain
Date: Sat, 02 Jul 2022 15:55:28 GMT
Content-Length: 2
hi
在console印出以下日誌。
2022/07/02 23:56:59 response status code=202, header={"Content-Type":["text/plain"]}, body=hi
沒有留言:
張貼留言