我正在尝试向timeoutGo 中的库添加一个选项,并编写了以下测试来模拟该行为。
func TestClientTimeout(t *testing.T) {
    backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        d := map[string]interface{}{
            "id":    "12",
            "scope": "test-scope",
        }
        time.Sleep(100 * time.Millisecond)
        e := json.NewEncoder(w)
        err := e.Encode(&d)
        if err != nil {
            t.Error(err)
        }
        w.WriteHeader(http.StatusOK)
    }))
    url := backend.URL
    ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
    defer cancel()
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        t.Error("Request error", err)
    }
    resp, err := http.DefaultClient.Do(req.WithContext(ctx))
    if err != nil {
        t.Error("Response error", err)
    }
    defer resp.Body.Close()
    t.Log(">>>>>>>Response is: ", resp)
}
但我总是低于错误,而不是 http.StatusGatewayTimeout
=== 运行 TestClientTimeout
--- 失败:TestClientTimeout (0.05s)
Run Code Online (Sandbox Code Playgroud)client_test.go:37: Timestamp before req 2018-07-13 09:10:14.936898 +0200 CEST m=+0.002048937 client_test.go:40: Response error Get http://127.0.0.1:49597: context deadline exceeded恐慌:运行时错误:无效的内存地址或零指针取消引用[已恢复]
恐慌:运行时错误:无效的内存地址或零指针取消引用
如何修复此测试,以返回带有http.StatusGatewayTimeout(504) 状态代码的响应?
你得到错误的原因context deadline exceeded是因为在超时context.Context请求的客户端是不是在服务器端处理程序的超时时间。这意味着context.Context客户端http.DefaultClient在写入任何响应之前放弃。
这panic: runtime error: invalid memory address...是因为您推迟关闭响应的正文,但响应是nil客户端返回错误。
这里响应为零,如果错误非零,则t.Error改为t.Fatal
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
if err != nil {
    // this should be t.Fatal, or don't do the body close if there's an error
    t.Error("Response error", err)
}
defer resp.Body.Close()
问题的真正根源http.StatusGatewayTimeout是服务器端超时,这意味着创建的任何超时都必须在服务器端。客户端http.DefaultClient永远不会创建它自己的服务器错误响应代码。
要创建服务器端超时,您可以将处理程序函数包装在http.TimeoutHandler:
handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    d := map[string]interface{}{
        "id":    "12",
        "scope": "test-scope",
    }
    time.Sleep(100 * time.Millisecond)
    e := json.NewEncoder(w)
    err := e.Encode(&d)
    if err != nil {
        t.Error(err)
    }
    w.WriteHeader(http.StatusOK)
})
backend := httptest.NewServer(http.TimeoutHandler(handlerFunc, 20*time.Millisecond, "server timeout"))
但是,这将创建503 - Service Unavailable错误响应代码。
要了解 504 的重要一点是,这是一个“网关”或“代理”错误响应代码。这意味着此代码不太可能来自实际处理请求的服务器。此代码更常见于负载均衡器和代理。
504 GATEWAY TIMEOUT 服务器在充当网关或代理时,没有收到上游服务器的及时响应,它需要访问以完成请求。
您已经http.Server在测试方法中使用了模拟 ,httptest.NewServer(...)因此您可以http.StatusGatewayTimeout在处理程序函数中手动返回响应状态。
handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusGatewayTimeout)
})
backend := httptest.NewServer(handlerFunc)
| 归档时间: | 
 | 
| 查看次数: | 7279 次 | 
| 最近记录: |