假设我有一个简单的服务器(为简洁起见,省略了错误处理):
func main() {
http.HandleFunc("/", HelloServer)
http.ListenAndServe(":8080", nil)
}
func HelloServer(w http.ResponseWriter, r *http.Request) {
b, _ := ioutil.ReadAll(r.Body)
fmt.Fprintf(w, "The request is: %s", string(b))
}
我需要添加一个简单的中间件,该中间件读取请求的主体并将其记录下来。我已经有了这个可行的解决方案:
func requestLogger(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
pr, pw := io.Pipe()
tee := io.TeeReader(r.Body, pw)
r.Body = pr
go func() {
body, _ := ioutil.ReadAll(tee)
defer pw.Close()
log.Printf("This is the logged request: %s", string(body))
}()
next(w, r)
}
}
我通过反复试验直观地找到了该解决方案,所以我不确定在所有情况下该方法是否都有效。这些是关于我自己的解决方案的问题:
Pipe
? 在r.Body上遇到EOF时,ioutil.ReadAll()
不会将其关闭。 TeeReader
从它通过管道(r.Body = pr)写入的同一源(r.Body)读取。根据文档,“写入PipeWriter”块直到满足一个或多个读取为止;对于TeeReader,必须在读取完成之前完成写入。 最佳答案
ioutil.ReadAll()在遇到EOF时不会关闭它吗?
Package ioutil
func ReadAll
func ReadAll(r io.Reader) ([]byte, error)
ReadAll从r读取直到出现错误或EOF并返回数据
读。
那不是记录的行为。另外,
io.Reader
也不是io.ReadCloser
。
关于go - 如何记录请求正文(通过中间件)而不进行缓冲?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59705848/