Golang中如何向http.TimeoutHandler传递自定义头部

Golang中如何向http.TimeoutHandler传递自定义头部 目前无法覆盖 http.TimeoutHandler 的内容类型(Content-Type)标头,因此无法渲染 JSON 消息,也无法将 Content-Type 标头设置为 JSON。是否有办法解决这个问题?

这个问题在这里也被提及过,但被忽略了。

响应始终是文本内容类型。

func TimeoutHandler(timeout time.Duration) func(next http.Handler) http.Handler {
 	return func(next http.Handler) http.Handler {
 		return http.TimeoutHandler(next, timeout, `{"key":"value"}`)
 	}
 }

更多关于Golang中如何向http.TimeoutHandler传递自定义头部的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何向http.TimeoutHandler传递自定义头部的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


http.TimeoutHandler 中设置自定义头部确实需要特殊处理,因为超时响应会绕过原始处理程序。以下是解决方案:

type timeoutWriter struct {
    http.ResponseWriter
    headersWritten bool
}

func (tw *timeoutWriter) WriteHeader(status int) {
    if !tw.headersWritten {
        tw.headersWritten = true
        tw.ResponseWriter.Header().Set("Content-Type", "application/json")
    }
    tw.ResponseWriter.WriteHeader(status)
}

func (tw *timeoutWriter) Write(b []byte) (int, error) {
    if !tw.headersWritten {
        tw.headersWritten = true
        tw.ResponseWriter.Header().Set("Content-Type", "application/json")
    }
    return tw.ResponseWriter.Write(b)
}

func TimeoutHandler(timeout time.Duration) func(next http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            tw := &timeoutWriter{ResponseWriter: w}
            
            handler := http.TimeoutHandler(next, timeout, `{"error":"request timeout"}`)
            handler.ServeHTTP(tw, r)
        })
    }
}

或者使用更简洁的包装器方法:

func JSONTimeoutHandler(h http.Handler, timeout time.Duration) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        
        timeoutHandler := http.TimeoutHandler(h, timeout, `{"error":"request timeout"}`)
        timeoutHandler.ServeHTTP(w, r)
    })
}

// 使用示例
func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
        time.Sleep(2 * time.Second) // 模拟耗时操作
        w.Write([]byte(`{"status":"ok"}`))
    })
    
    handler := JSONTimeoutHandler(mux, 1*time.Second)
    http.ListenAndServe(":8080", handler)
}

对于更复杂的场景,可以创建自定义超时处理器:

type jsonTimeoutHandler struct {
    handler http.Handler
    timeout time.Duration
    body    string
}

func (h *jsonTimeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    done := make(chan struct{})
    
    go func() {
        h.handler.ServeHTTP(w, r)
        close(done)
    }()
    
    select {
    case <-done:
        return
    case <-time.After(h.timeout):
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusServiceUnavailable)
        w.Write([]byte(h.body))
    }
}

func NewJSONTimeoutHandler(handler http.Handler, timeout time.Duration, timeoutBody string) http.Handler {
    return &jsonTimeoutHandler{
        handler: handler,
        timeout: timeout,
        body:    timeoutBody,
    }
}

这些方法确保超时响应始终返回正确的 JSON Content-Type 头部。

回到顶部