使用中间件实现Golang net/http ServeMux的自定义错误响应

使用中间件实现Golang net/http ServeMux的自定义错误响应 我正在尝试在使用 net/http 的 ServeMux 时,为“未找到”和“方法不允许”的响应返回 JSON 格式的响应。我通过中间件实现了这个功能,并希望得到关于如何改进的反馈。另外,如果有更简单的方法,也请告诉我。谢谢!

type ResponseWriterInterceptor struct {
	w      http.ResponseWriter
	status int
}

func (i *ResponseWriterInterceptor) Header() http.Header {
	return i.w.Header()
}
func (i *ResponseWriterInterceptor) Write(b []byte) (int, error) {
	if string(b) == "Method Not Allowed\n" || string(b) == "404 page not found\n" {
		return 0, nil
	}
	return i.w.Write(b)
}

func (i *ResponseWriterInterceptor) WriteHeader(statusCode int) {
	i.status = statusCode
}

func (app *application) JSONError(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		i := &ResponseWriterInterceptor{w: w}
		next.ServeHTTP(i, r)

		switch i.status {
		case http.StatusNotFound:
			app.notFoundResponse(w, r)
		case http.StatusMethodNotAllowed:
			app.methodNotAllowedResponse(w, r)
		}
	})
}

更多关于使用中间件实现Golang net/http ServeMux的自定义错误响应的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于使用中间件实现Golang net/http ServeMux的自定义错误响应的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的中间件实现思路正确,但存在几个关键问题需要改进。以下是优化后的版本:

type ResponseWriterInterceptor struct {
    http.ResponseWriter
    status int
    body   []byte
}

func (i *ResponseWriterInterceptor) WriteHeader(statusCode int) {
    i.status = statusCode
    i.ResponseWriter.WriteHeader(statusCode)
}

func (i *ResponseWriterInterceptor) Write(b []byte) (int, error) {
    if i.status == http.StatusNotFound || i.status == http.StatusMethodNotAllowed {
        i.body = b
        return len(b), nil
    }
    return i.ResponseWriter.Write(b)
}

func (app *application) JSONError(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        interceptor := &ResponseWriterInterceptor{ResponseWriter: w}
        next.ServeHTTP(interceptor, r)

        switch interceptor.status {
        case http.StatusNotFound:
            app.notFoundResponse(w, r)
        case http.StatusMethodNotAllowed:
            app.methodNotAllowedResponse(w, r)
        }
    })
}

更简洁的方法是直接使用自定义的 ServeMux

type JSONServeMux struct {
    *http.ServeMux
    app *application
}

func (m *JSONServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    handler, pattern := m.Handler(r)
    
    if pattern == "" {
        m.app.notFoundResponse(w, r)
        return
    }
    
    handler.ServeHTTP(w, r)
}

func (m *JSONServeMux) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
    m.ServeMux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
        if r.Method != http.MethodGet && pattern == r.URL.Path {
            m.app.methodNotAllowedResponse(w, r)
            return
        }
        handler(w, r)
    })
}

使用示例:

mux := &JSONServeMux{
    ServeMux: http.NewServeMux(),
    app:      app,
}

mux.HandleFunc("/api/users", app.handleUsers)
http.ListenAndServe(":8080", mux)

这种方法避免了中间件的复杂性,直接在路由层处理错误响应。

回到顶部