57人参与 • 2025-02-14 • Golang
go使用连接池进行http请求,一般都能请求成功,但偶然会出现请求失败返回eof错误的情况;类似java的org.apache.http.nohttpresponseexception
客户端通过keep alive机制保障性能,简单理解就是复用tcp五元会话,用于进行多次http请求;但如果服务端的空闲保活时间是10s,在第一次请求完的10s进行了第二次请求,此时客户端认为连接仍然有效继续发起请求,但服务端发出了fin报文不再对此连接进行响应,从而导致客户端请求失败并出现eof错误。
偶发就是因为两个时间要恰好碰到一起才可能触发这个问题
解决方式:
package main import ( "bytes" "crypto/tls" "encoding/json" "errors" "fmt" "io" "io/ioutil" "net/http" "time" ) func main() { // 创建自定义的 transport,设置连接池参数 tr := &http.transport{ tlsclientconfig: &tls.config{ insecureskipverify: true, // 忽略 tls 证书验证 }, maxidleconns: 1, // 限制最大空闲连接数为1 maxidleconnsperhost: 1, // 限制每个host最大空闲连接数为1 idleconntimeout: 20 * time.second, // 本地空闲连接超时设置为20s disablekeepalives: false, // 启用 keep-alive maxconnsperhost: 1, // 限制每个host的最大连接数为1,强制复用连接 forceattempthttp2: false, // 禁用 http/2 } // 创建 http 客户端 client := &http.client{ transport: tr, timeout: 5 * time.second, // 设置请求超时时间 } // 准备请求参数 url := "https://192.168.24.70:2018/api/zguard/sysmng/syscfg/basecfg/sysname/651d5b9f-225b-4c8c-9f06-80bfad3fa977" cookie := "session-id=f416b188c91bc72a06853b362d5cb7b3a6b68a43" // 准备请求体数据 requestbody := map[string]string{ "sys_name": "n-guard", } // 将 map 转换为 json jsonbody, err := json.marshal(requestbody) if err != nil { fmt.printf("json 编码失败: %v\n", err) } // 循环发送请求,模拟使用已关闭的连接 for i := 0; i < 5; i++ { // 只测试两次请求即可 // 每次请求都创建新的 bytes.buffer,确保 body 可以重复读取 bodyreader := bytes.newbuffer(jsonbody) req, err := http.newrequest("put", url, bodyreader) if err != nil { fmt.printf("创建请求失败: %v\n", err) continue } // 设置 content-length req.contentlength = int64(len(jsonbody)) // 设置请求头 req.header.set("cookie", cookie) req.header.set("content-type", "application/json") fmt.printf("发送第 %d 个请求...\n", i+1) // 发送请求 resp, err := client.do(req) if err != nil { fmt.printf("请求失败: %v\n", err) if errors.is(err, io.eof) { fmt.printf("连接不再可用: 重试:新的五元重新发起连接\n") bodyreader := bytes.newbuffer(jsonbody) reqretry, err := http.newrequest("put", url, bodyreader) if err != nil { fmt.printf("创建请求失败: %v\n", err) continue } // 设置 content-length reqretry.contentlength = int64(len(jsonbody)) // 设置请求头 reqretry.header.set("cookie", cookie) reqretry.header.set("content-type", "application/json") resp, err = client.do(reqretry) if err != nil { fmt.printf("err:\n", err) continue } } else { continue } } // 读取响应 body, err := ioutil.readall(resp.body) if err != nil { fmt.printf("读取响应失败: %v\n", err) } resp.body.close() fmt.printf("请求 %d - 状态码: %d, 响应: %s\n", i+1, resp.statuscode, string(body)) fmt.println("等待10秒后发送第二个请求...") time.sleep(10 * time.second) // 等待10秒,此时服务端已经关闭连接(10s) time.sleep(500 * time.millisecond) } }
[xiaofeng@localhost httpkeepalive]$ go run main.go
发送第 1 个请求...
请求 1 - 状态码: 200, 响应: {"code":0,"result":"0","message":"成功"}
等待10秒后发送第二个请求...
发送第 2 个请求...
请求 2 - 状态码: 200, 响应: {"code":0,"result":"0","message":"成功"}
等待10秒后发送第二个请求...
发送第 3 个请求...
请求失败: put "https://192.168.24.70:2018/api/zguard/sysmng/syscfg/basecfg/sysname/651d5b9f-225b-4c8c-9f06-80bfad3fa977": eof
连接不再可用: 重试:新的五元重新发起连接
请求 3 - 状态码: 200, 响应: {"code":0,"result":"0","message":"成功"}
等待10秒后发送第二个请求...
发送第 4 个请求...
请求失败: put "https://192.168.24.70:2018/api/zguard/sysmng/syscfg/basecfg/sysname/651d5b9f-225b-4c8c-9f06-80bfad3fa977": eof
连接不再可用: 重试:新的五元重新发起连接
请求 4 - 状态码: 200, 响应: {"code":0,"result":"0","message":"成功"}
等待10秒后发送第二个请求...
发送第 5 个请求...
请求 5 - 状态码: 200, 响应: {"code":0,"result":"0","message":"成功"}
等待10秒后发送第二个请求...
到此这篇关于go进行http请求偶发eof问题分析的文章就介绍到这了,更多相关go http请求偶发eof内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论