Go HTTP ListenAndServe记录响应日志

huangapple go评论82阅读模式
英文:

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只是headerbodyresponse code,所以你可以在ResponseWriter上使用Header()方法来获取header,然后在将其写入ResponseWriter之前记录response codebody

如果你提供你想要做的事情的示例,我可以详细说明如何实现。

以下是我为一个小项目修复此问题的方法:
我在所有的处理程序中都使用了以下代码:

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.

huangapple
  • 本文由 发表于 2016年4月19日 07:32:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/36706033.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定