英文:
Go HTTP ListenAndServe logging response
问题
我想知道在使用ListenAndServe时是否有一种方法可以记录响应。
据我所知,处理程序没有访问"Response"对象的权限,只有一个ResponseWriter,因此我无法调用httputil.DumpResponse。
英文:
I was wondering if there is a way to log the responses when using ListenAndServe.
As far as I can tell, the handler doesn't have access to a "Response" object. Just a ResponseWriter, so I cannot call httputil.DumpResponse.
答案1
得分: 7
http.ResponseWriter是一个接口。您可以使用嵌入来扩展它以进行日志记录,如下所示。
package main
import (
"log"
"net/http"
)
func sampleHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
response := []byte("Sample Response")
w.Write(response)
}
type loggingResponseWriter struct {
status int
body string
http.ResponseWriter
}
func (w *loggingResponseWriter) WriteHeader(code int) {
w.status = code
w.ResponseWriter.WriteHeader(code)
}
func (w *loggingResponseWriter) Write(body []byte) (int, error) {
w.body = string(body)
return w.ResponseWriter.Write(body)
}
func responseLogger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
loggingRW := &loggingResponseWriter{
ResponseWriter: w,
}
h.ServeHTTP(loggingRW, r)
log.Println("Status : ", loggingRW.status, "Response : ", loggingRW.body)
})
}
func main() {
http.Handle("/", responseLogger(http.HandlerFunc(sampleHandler)))
http.ListenAndServe(":8080", nil)
}
您可以使用responseLogger包装要记录响应的处理程序函数。
英文:
http.ResponseWriter is an interface. You can use embedding to extend it for logging as follows.
package main
import (
"log"
"net/http"
)
func sampleHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
response := []byte("Sample Response")
w.Write(response)
}
type loggingResponseWriter struct {
status int
body string
http.ResponseWriter
}
func (w *loggingResponseWriter) WriteHeader(code int) {
w.status = code
w.ResponseWriter.WriteHeader(code)
}
func (w *loggingResponseWriter) Write(body []byte) (int, error) {
w.body = string(body)
return w.ResponseWriter.Write(body)
}
func responseLogger(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
loggingRW := &loggingResponseWriter{
ResponseWriter: w,
}
h.ServeHTTP(loggingRW, r)
log.Println("Status : ", loggingRW.status, "Response : ", loggingRW.body)
})
}
func main() {
http.Handle("/", responseLogger(http.HandlerFunc(sampleHandler)))
http.ListenAndServe(":8080", nil)
}
You can wrap the handler functions that you want to log responses for with responseLogger.
答案2
得分: 1
你无法在将其写入ResponseWriter
之前获取响应,因为从技术上讲,响应在你写入它之前是不存在的。
但是在处理程序函数中,response
只是header
、body
和response code
,所以你可以在ResponseWriter
上使用Header()
方法来获取header,然后在将其写入ResponseWriter
之前记录response code
和body
。
如果你提供你想要做的事情的示例,我可以详细说明如何实现。
以下是我为一个小项目修复此问题的方法:
我在所有的处理程序中都使用了以下代码:
type transaction struct {
res Response // 也要创建这个类型
req Request // 也要创建这个类型
}
func NewTransaction(w http.ResponseWriter, req *http.Request) *transaction{}
Log := make(chan transaction, 100)
go func{
// 从通道中读取并以你想要的方式记录信息。
}()
func indexHandler(w http.ResponseWriter, req *http.Request) {
tx := NewTransaction(w, req) // 包含请求和响应的结构体
defer func() {
Log <- tx
}()
/*
在这里处理请求
*/
// 更新请求和响应
Request.Body = body
}
在处理程序函数的末尾,在提供所请求的数据之后,更新请求和响应的值。
并且有一个goroutine监听Log通道并执行所有的日志记录。
此外,你可以编写一个包装函数来提供文件并返回响应。
英文:
You can't because the response technically doesn't exist until you write it to the ResponseWriter
.
But in the response
is just the header
, body
and response code
so in the handler function you can use method Header()
on the ResponseWriter
to get the header and then you can log the response code
and the body
before you write it to the ResponseWriter
.
If you provide an example of what you are trying to do, I can elaborate on how to do it.
This is what I did to fix this for a small project:
I use this in all my handlers:
type transaction struct {
res Response // Create this type also
req Request // Create this type also
}
func NewTransaction(w http.ResponseWriter, req *http.Request) *transaction{}
Log := make(chan transaction, 100)
go func{
// Read from channel and log the info however you want.
}()
func indexHandler(w http.ResponseWriter, req *http.Request) {
tx := NewTransaction(w, req) // Struct with the request and response
defer func() {
Log <- tx
}()
/*
Handle request here
*/
// Update request and response
Request.Body = body
}
And at the end of the handler function, after having served the requested data, I update the values for the request and the response.
And have a goroutine listening to the channel Log and doing all your logging.
Also you can write a wrapper function that serves the file and returns the response.
答案3
得分: -1
作为替代方案,可以使用fasthttp。
英文:
As an alternative, one can use fasthttp.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论