http - 如何在 Go 中的测试中模拟 http 请求的 504 超时错误?
问题描述
我正在尝试向timeout
Go 中的库添加一个选项,并编写了以下测试来模拟该行为。
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 (0.05s)
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
恐慌:运行时错误:无效的内存地址或 nil 指针取消引用 [已恢复]
恐慌:运行时错误:无效的内存地址或零指针取消引用
如何修复此测试,以返回带有http.StatusGatewayTimeout
(504) 状态码的响应?
解决方案
您收到错误context deadline exceeded
的原因是context.Context
请求客户端的超时时间短于服务器端处理程序中的超时时间。这意味着context.Context
客户端http.DefaultClient
在写入任何响应之前就放弃了。
这panic: runtime error: invalid memory address...
是因为您推迟关闭响应的正文,但响应是nil
客户端返回错误。
这里响应为 nil,如果错误为非 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)
推荐阅读
- mysql - 如果插入有效,那么
- python - Python pandas:爆炸多行
- javascript - 使用 MongoDB 进行模糊字符串搜索的有效方法
- python - 如何使用 BeautifulSoup 跳过空白?
- jquery - 更改 1 个数据值而不更改所有三个
- angular - 使用 Angular 9 将参数传递给构造函数会生成 ng2003 错误
- google-chrome - Microsoft Edge 的 Margin-top 与 google 不同
- discord.js - 如何使此命令仅由管理员使用?
- c# - C# Apicontroller 捕获响应
- blazor - Blazor 服务器托管:为什么在调试时看不到任何网络请求?