在使用 net/http
库时,我们可能会遇到无法直接获取 HTTP 响应状态码的问题。为了优化这一点,我们可以采用以下两种方案:
方案一:自定义 ResponseWriter
我们可以通过实现一个自定义的 ResponseWriter
来获取 HTTP 响应状态码。具体步骤如下:
- 创建一个结构体,嵌入
http.ResponseWriter
并添加一个字段用于存储状态码。 - 实现
WriteHeader
方法,在调用原始 ResponseWriter
的 WriteHeader
方法之前,记录状态码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| package main
import (
"fmt"
"net/http"
)
type CustomResponseWriter struct {
http.ResponseWriter
StatusCode int
}
func (w *CustomResponseWriter) WriteHeader(code int) {
w.StatusCode = code
w.ResponseWriter.WriteHeader(code)
}
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
crw := &CustomResponseWriter{ResponseWriter: w}
handler(crw, r)
fmt.Printf("Response status code: %d\n", crw.StatusCode)
})
http.ListenAndServe(":8080", nil)
}
|
方案二:使用 httpsnoop
包
httpsnoop
是一个第三方库,可以帮助我们更方便地获取 HTTP 响应状态码。使用方法如下:
安装 httpsnoop
包:
1
| go get -u github.com/felixge/httpsnoop
|
使用 httpsnoop.CaptureMetrics
包装处理函数,从返回的 Metrics
中获取状态码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| package main
import (
"fmt"
"net/http"
"github.com/felixge/httpsnoop"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "Hello, World!")
}
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
m := httpsnoop.CaptureMetrics(next, w, r)
fmt.Println("code: ", m.Code, "time: ", m.Duration, "length: ", m.Written)
})
}
func main() {
http.Handle("/", middleware(http.HandlerFunc(handler)))
http.ListenAndServe(":8080", nil)
}
|
更高阶的使用方法
我们还可以使用 httpsnoop.Wrap
和 httpsnoop.Hooks
来实现更高阶的功能,例如记录更多的请求和响应信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| package main
import (
"fmt"
"net/http"
"github.com/felixge/httpsnoop"
)
func handler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, "Hello, World!")
}
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var _code int
// 通过替换 WriteHeader 的实现,获取到 code
_w := httpsnoop.Wrap(w, httpsnoop.Hooks{WriteHeader: func(headerFunc httpsnoop.WriteHeaderFunc) httpsnoop.WriteHeaderFunc {
return func(code int) {
_code = code
headerFunc(code)
}
}})
next.ServeHTTP(_w, r)
fmt.Println("code: ", _code)
})
}
func main() {
http.Handle("/", middleware(http.HandlerFunc(handler)))
http.ListenAndServe(":8080", nil)
}
|
通过以上两种简单方案和一种高阶方案,我们可以有效地获取 HTTP 响应状态码,从而更好地处理和记录请求的应答信息。