Golang中如何设置带JSON响应头和正文的http.TimeoutHandler
Golang中如何设置带JSON响应头和正文的http.TimeoutHandler 你好,
有没有办法在使用 http.TimeoutHandler 时返回一个 JSON 响应体,并设置 application/json; charset=utf-8 内容类型头?
谢谢
2 回复
我不太了解 http.TimeoutHandler,但这里有一个使用 context 的想法:
func handlerWithTimeout(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
result := make(chan string)
go func() {
result <- slowOperation()
}()
select {
case r := <-result:
io.WriteString(w, r+"\n")
case <-ctx.Done():
w.Header().Add("content-type", "application/json")
w.WriteHeader(http.StatusServiceUnavailable)
d := map[string]string{"error": "timeout"}
err := json.NewEncoder(w).Encode(d)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
}
}
}
func slowOperation() string {
fmt.Println("Working on it...")
time.Sleep(2 * time.Second)
return "data"
}
更多关于Golang中如何设置带JSON响应头和正文的http.TimeoutHandler的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中,可以通过自定义超时响应处理器来实现带JSON响应头和正文的http.TimeoutHandler。以下是实现方法:
package main
import (
"encoding/json"
"net/http"
"time"
)
// 自定义超时响应处理器
type jsonTimeoutHandler struct {
handler http.Handler
body interface{}
timeout time.Duration
}
func (h *jsonTimeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 创建带缓冲的ResponseWriter
rw := &responseWriter{
ResponseWriter: w,
status: http.StatusOK,
body: []byte{},
}
// 使用TimeoutHandler包装原始处理器
timeoutHandler := http.TimeoutHandler(h.handler, h.timeout, "Request timeout")
// 执行请求处理
timeoutHandler.ServeHTTP(rw, r)
// 如果发生超时(状态码503),返回自定义JSON响应
if rw.status == http.StatusServiceUnavailable {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(h.body)
return
}
// 正常响应,写入原始响应
for k, v := range rw.Header() {
w.Header()[k] = v
}
w.WriteHeader(rw.status)
w.Write(rw.body)
}
// 自定义ResponseWriter用于捕获响应
type responseWriter struct {
http.ResponseWriter
status int
body []byte
}
func (rw *responseWriter) WriteHeader(status int) {
rw.status = status
rw.ResponseWriter.WriteHeader(status)
}
func (rw *responseWriter) Write(b []byte) (int, error) {
rw.body = append(rw.body, b...)
return rw.ResponseWriter.Write(b)
}
// 使用示例
func main() {
// 定义超时JSON响应体
timeoutResponse := map[string]string{
"error": "Request timeout",
"message": "The request took too long to process",
}
// 创建自定义超时处理器
handler := &jsonTimeoutHandler{
handler: http.HandlerFunc(yourHandler),
body: timeoutResponse,
timeout: 5 * time.Second,
}
http.Handle("/", handler)
http.ListenAndServe(":8080", nil)
}
func yourHandler(w http.ResponseWriter, r *http.Request) {
// 模拟长时间处理
time.Sleep(10 * time.Second)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]string{
"status": "success",
})
}
更简洁的实现方式:
package main
import (
"encoding/json"
"net/http"
"time"
)
func jsonTimeoutHandler(next http.Handler, timeout time.Duration, timeoutBody interface{}) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 创建通道用于检测超时
done := make(chan bool, 1)
go func() {
next.ServeHTTP(w, r)
done <- true
}()
select {
case <-done:
return
case <-time.After(timeout):
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(timeoutBody)
}
})
}
// 使用示例
func main() {
timeoutResponse := map[string]interface{}{
"error": "Request timeout",
"code": 408,
"timeout": 5,
}
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(10 * time.Second)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]string{"result": "success"})
})
wrappedHandler := jsonTimeoutHandler(handler, 5*time.Second, timeoutResponse)
http.Handle("/", wrappedHandler)
http.ListenAndServe(":8080", nil)
}
直接包装http.TimeoutHandler的版本:
package main
import (
"encoding/json"
"net/http"
"time"
)
func JSONTimeoutHandler(h http.Handler, dt time.Duration, msg string) http.Handler {
timeoutResponse := map[string]string{
"error": msg,
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 使用标准TimeoutHandler
timeoutHandler := http.TimeoutHandler(h, dt, msg)
// 创建包装器来拦截响应
rw := &jsonResponseWriter{
ResponseWriter: w,
originalWriter: w,
}
timeoutHandler.ServeHTTP(rw, r)
// 如果是超时响应,返回JSON
if rw.timeoutTriggered {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusServiceUnavailable)
json.NewEncoder(w).Encode(timeoutResponse)
}
})
}
type jsonResponseWriter struct {
http.ResponseWriter
originalWriter http.ResponseWriter
timeoutTriggered bool
}
func (w *jsonResponseWriter) WriteHeader(code int) {
if code == http.StatusServiceUnavailable {
w.timeoutTriggered = true
return
}
w.originalWriter.WriteHeader(code)
}
func (w *jsonResponseWriter) Write(b []byte) (int, error) {
if w.timeoutTriggered {
return len(b), nil
}
return w.originalWriter.Write(b)
}
// 使用示例
func main() {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(10 * time.Second)
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
})
wrappedHandler := JSONTimeoutHandler(handler, 5*time.Second, "Request timeout")
http.Handle("/", wrappedHandler)
http.ListenAndServe(":8080", nil)
}

