问题描述
我有一个客户端和服务器。服务器处理请求超过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)