Golang中的响应中间件(附实例)

224 阅读1分钟

这个例子将帮助你捕获响应状态代码和正文大小,然后记录它。如果你愿意,你也可以记录与请求有关的数据,但这不在本篇文章的范围之内。

响应写入器

package response

import (
	"bufio"
	"fmt"
	"net"
	"net/http"
)

// Acts as an adapter for `http.ResponseWriter` type to store response status
// code and size.
type ResponseWriter struct {
	http.ResponseWriter

	code int
	size int
}

// Returns a new `ResponseWriter` type by decorating `http.ResponseWriter` type.
func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
	return &ResponseWriter{
		ResponseWriter: w,
	}
}

// Overrides `http.ResponseWriter` type.
func (r *ResponseWriter) WriteHeader(code int) {
	if r.Code() == 0 {
		r.code = code
		r.ResponseWriter.WriteHeader(code)
	}
}

// Overrides `http.ResponseWriter` type.
func (r *ResponseWriter) Write(body []byte) (int, error) {
	if r.Code() == 0 {
		r.WriteHeader(http.StatusOK)
	}

	var err error
	r.size, err = r.ResponseWriter.Write(body)

	return r.size, err
}

// Overrides `http.Flusher` type.
func (r *ResponseWriter) Flush() {
	if fl, ok := r.ResponseWriter.(http.Flusher); ok {
		if r.Code() == 0 {
			r.WriteHeader(http.StatusOK)
		}

		fl.Flush()
	}
}

// Overrides `http.Hijacker` type.
func (r *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	hj, ok := r.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, fmt.Errorf("the hijacker interface is not supported")
	}

	return hj.Hijack()
}

// Returns response status code.
func (r *ResponseWriter) Code() int {
	return r.code
}

// Returns response size.
func (r *ResponseWriter) Size() int {
	return r.size
}

访问记录器

package middleware

import (
	"log"
	"net/http"

	"response"
)

// AccessLoger helps logging request and response related data.
func AccessLoger(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		rw := response.NewResponseWriter(w)

		h.ServeHTTP(rw, r)

		log.Println("status:", rw.Code(), "size:", rw.Size(), "bytes")
	})
}

服务器

package http

import (
	"net/http"
)

// NewServer returns `http.Server` pointer type.
func NewServer(address string, handler http.Handler) *http.Server {
	return &http.Server{
		Addr:    address,
		Handler: AccessLoger(handler),
	}
}

测试

如果你向你的一个端点发送一个请求的例子,日志应该看起来像下面这样:

2021/01/27 17:19:39 status: 200 size: 63 bytes