使用HTTP 200 OK防止超过上下文截止期限在等待标头时超过了Client.Timeout错误

问题描述

我有一个客户端和服务器。服务器处理请求超过2秒。但是客户没有那么多时间。它需要在1秒内得到响应。这就是为什么它会回应

获取“ http:// localhost:8888”:超出上下文截止日期(在等待标头时超过了Client.Timeout) 紧急:运行时错误:无效的内存地址或nil指针取消引用

有问题吗? 如何以正确恢复所有错误的方式更改server.go 并且端点始终可用? 注意,客户端正在呼叫的端点应尽快处理请求,并在完成后立即返回200 OK。

client.go

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {

    c := &http.Client{Timeout: 2 * time.Second}

    res,err := c.Get("http://localhost:8888")
    if err != nil {
        log.Println(err)
    }
    var r []byte

    _,err = res.Body.Read(r)
    fmt.Println(string(r))
}

server.go

package main

import (
    "fmt"
    "io"
    "net/http"
    "time"
)

func slowHandler(w http.ResponseWriter,req *http.Request) {
    time.Sleep(2 * time.Second)
    io.WriteString(w,"I am slow!\n")
}

func main() {
    srv := http.Server{
        Addr:    ":8888",Handler: http.HandlerFunc(slowHandler),}

    if err := srv.ListenAndServe(); err != nil {
        fmt.Printf("Server Failed: %s\n",err)
    }
}

解决方法

您可以通过实施恢复中间件来从恐慌中恢复,例如:

 defer func() {
      if err := recover(); err != nil {
        log.Println("recovered from panic",err)
        fmt.Fprintf(w,"recovered from panic")
      }
    }()

您可以将此有用的文章用作准则https://www.nicolasmerouze.com/middlewares-golang-best-practices-examples

编辑

您可以创建自定义中间件来处理自定义处理程序超时

func timeOutMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter,r *http.Request) {
        done := make(chan bool)
        ctx,cancelFunc := context.WithTimeout(r.Context(),time.Second*1)
        defer cancelFunc()
        go func() {
            next.ServeHTTP(w,r)
            close(done)
        }()
        select {
        case <-done:
            return
        case <-ctx.Done():
            w.WriteHeader(http.StatusOK)
            w.Write([]byte(`{"message": "handled time out"}`))
        }
    })

}

要使其正常工作,您需要与客户端同步,因为如果客户端设置的超时时间过短,则永远不会获得正确的响应,或者在服务器设置的超时时间过短的情况下,也会发生这种情况。 / p>

要完全读取响应字节,请使用此

defer res.Body.Close()
body,_ := ioutil.ReadAll(res.Body)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...