Golang中解决F5 bigip请求头等待超时问题(Context Deadline Exceeded)
Golang中解决F5 bigip请求头等待超时问题(Context Deadline Exceeded) 我目前正尝试使用Go语言来管理我们F5 BigIP的某些方面。我找到了两个有助于与F5交互的包。
- https://godoc.org/github.com/scottdware/go-bigip
- https://godoc.org/github.com/e-XpertSolutions/f5-rest-client/f5
对于这两个包,在尝试调用F5时,我都遇到了相同的错误。
Get "https://<f5-ipaddress>/mgmt/tm/ltm/virtual/": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
以下是我为这两个包使用的代码。
package main
import (
"fmt"
"github.com/e-XpertSolutions/f5-rest-client/f5"
"github.com/e-XpertSolutions/f5-rest-client/f5/ltm"
"github.com/scottdware/go-bigip"
)
func main() {
f5Client, err := f5.NewBasicClient("https://<f5-ipaddress>", "username", "password")
if err != nil {
fmt.Println(err)
}
f5Client.DisableCertCheck()
ltmClient := ltm.New(f5Client)
vsConfigList, err := ltmClient.Virtual().ListAll()
if err != nil {
fmt.Println(err)
}
fmt.Println(vsConfigList)
config := bigip.ConfigOptions{
APICallTimeout: 10000,
}
f5 := bigip.NewSession("https://<f5-ipaddress>", "username", "password", &config)
vservers, err := f5.VirtualServers()
if err != nil {
fmt.Println("THERE WAS AN ERROR")
fmt.Println(err)
}
fmt.Println(vservers)
test, err := f5.GetVirtualServer("virtual-server-name")
if err != nil {
fmt.Println("THERE WAS AN ERROR")
fmt.Println(err)
}
fmt.Println(test)
for _, vs := range vservers.VirtualServers {
fmt.Printf("Name: %s\n", vs.Name)
}
}
由于我从两个包都收到了相同的错误,我感觉我可能没有理解某些东西。
更多关于Golang中解决F5 bigip请求头等待超时问题(Context Deadline Exceeded)的实战教程也可以访问 https://www.itying.com/category-94-b0.html
原来“APICallTimeout”的单位是纳秒,所以我设置的计时器时间太短了。我将其调整为 APICallTimeout: 100 * time.Second,问题就解决了。
APICallTimeout: 100 * time.Second
更多关于Golang中解决F5 bigip请求头等待超时问题(Context Deadline Exceeded)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这个错误通常是由于客户端等待服务器响应头的时间超过了设置的超时时间。在Go中,你可以通过配置HTTP客户端的超时设置来解决这个问题。以下是针对这两个包的解决方案:
对于 go-bigip 包:
package main
import (
"crypto/tls"
"fmt"
"net/http"
"time"
"github.com/scottdware/go-bigip"
)
func main() {
// 创建自定义的HTTP客户端
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
}
client := &http.Client{
Transport: tr,
Timeout: 30 * time.Second, // 设置总超时时间
}
config := bigip.ConfigOptions{
APICallTimeout: 30000, // 30秒
HTTPClient: client, // 传入自定义HTTP客户端
}
f5 := bigip.NewSession("https://<f5-ipaddress>", "username", "password", &config)
vservers, err := f5.VirtualServers()
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println(vservers)
}
对于 f5-rest-client 包:
package main
import (
"crypto/tls"
"fmt"
"net/http"
"time"
"github.com/e-XpertSolutions/f5-rest-client/f5"
"github.com/e-XpertSolutions/f5-rest-client/f5/ltm"
)
func main() {
// 创建自定义的HTTP客户端
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
ResponseHeaderTimeout: 15 * time.Second, // 专门设置响应头超时
}
client := &http.Client{
Transport: tr,
Timeout: 30 * time.Second,
}
// 使用自定义HTTP客户端创建F5客户端
f5Client, err := f5.NewClient("https://<f5-ipaddress>", "username", "password", client)
if err != nil {
fmt.Println(err)
return
}
ltmClient := ltm.New(f5Client)
vsConfigList, err := ltmClient.Virtual().ListAll()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(vsConfigList)
}
通用解决方案 - 创建可重用的HTTP客户端工厂函数:
package main
import (
"crypto/tls"
"net/http"
"time"
)
func createF5HTTPClient() *http.Client {
return &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true, // 跳过证书验证
},
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
ResponseHeaderTimeout: 20 * time.Second, // 关键:设置响应头等待超时
ExpectContinueTimeout: 1 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
},
Timeout: 45 * time.Second, // 总超时时间
}
}
// 使用示例
func main() {
httpClient := createF5HTTPClient()
// 对于 go-bigip
config := bigip.ConfigOptions{
APICallTimeout: 45000,
HTTPClient: httpClient,
}
// 对于 f5-rest-client
f5Client, err := f5.NewClient("https://<f5-ipaddress>", "username", "password", httpClient)
// ... 后续代码
}
调试版本 - 添加详细日志:
package main
import (
"crypto/tls"
"fmt"
"log"
"net/http"
"net/http/httputil"
"time"
)
type loggingTransport struct {
transport http.RoundTripper
}
func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
// 记录请求
dump, _ := httputil.DumpRequestOut(req, true)
log.Printf("Request:\n%s", dump)
start := time.Now()
resp, err := t.transport.RoundTrip(req)
elapsed := time.Since(start)
if err != nil {
log.Printf("Request failed after %v: %v", elapsed, err)
} else {
log.Printf("Request completed in %v", elapsed)
}
return resp, err
}
func createDebugHTTPClient() *http.Client {
baseTransport := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
ResponseHeaderTimeout: 25 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
}
return &http.Client{
Transport: &loggingTransport{transport: baseTransport},
Timeout: 60 * time.Second,
}
}
关键点:
ResponseHeaderTimeout是解决 “awaiting headers” 错误的关键参数- 适当增加超时时间(F5设备响应可能较慢)
- 考虑网络延迟和设备负载情况调整超时值
- 使用自定义HTTP客户端可以更精细地控制连接行为

