You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang请求API报connection reset by peer 同环境curl/Python正常

Golang调用Qualys API触发connection reset by peer问题解决

问题描述

同一机器环境下,使用curl、Python requests库发起完全相同的Qualys平台API请求可正常获得响应,使用Golang标准库net/http编写的HTTP客户端发起相同请求时始终返回错误:read: connection reset by peer。已在Go 1.10.8、1.17.2、1.18.3三个版本测试,均稳定复现该问题。

复现信息

  • 接口预期返回内容
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE SIMPLE_RETURN SYSTEM "https://qualysapi.qg2.apps.qualys.eu/api/2.0/simple_return.dtd">
<SIMPLE_RETURN>
  <RESPONSE>
    <DATETIME>2022-07-02T07:50:26Z</DATETIME>
    <CODE>2000</CODE>
    <TEXT>Bad Login/Password</TEXT>
  </RESPONSE>
</SIMPLE_RETURN>
  • 可正常执行的curl命令
curl -H "X-Requested-With:curl" -u "asdf:asdfdasf" "https://qualysguard.qg2.apps.qualys.eu/api/2.0/fo/asset/host/?action=list"
  • 可正常执行的Python代码
# test.py
import requests


url = 'https://qualysguard.qg2.apps.qualys.eu/api/2.0/fo/asset/host/?action=list'
res = requests.get(url,
                   headers={"X-Requested-With": "curl"},
                   auth=("asdf", "asdfas"))
print(res.text)

执行命令python3 test.py即可正常获得接口返回。

  • 运行失败的Golang代码
package main

import (
    "encoding/base64"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    url := "https://qualysguard.qg2.apps.qualys.eu/api/2.0/fo/asset/host/?action=list"

    client := http.Client{}
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
      panic(err)
    }

    req.Header.Set("X-Requested-With", "curl")
    req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("asdf:asdfas")))

    resp, err := client.Do(req)
    if err != nil {
        panic(err)
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatalln(err)
    }
    sb := string(body)

    fmt.Println(sb)
}

根因

Qualys欧洲区qg2节点的API网关对HTTP/2协议的兼容存在缺陷,Golang默认的HTTP客户端会在TLS握手时通过ALPN协商优先使用HTTP/2协议,网关识别到HTTP/2请求后会直接重置连接,触发connection reset by peer错误。而curl、Python requests默认优先使用HTTP/1.1协议,不会触发该网关bug。

修复方案

自定义HTTP客户端Transport配置,强制禁用HTTP/2协商,让客户端走HTTP/1.1协议发起请求即可,修改后的可正常运行Golang代码如下:

package main

import (
	"crypto/tls"
	"encoding/base64"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {
	url := "https://qualysguard.qg2.apps.qualys.eu/api/2.0/fo/asset/host/?action=list"

	// 自定义Transport,禁用HTTP/2协商
	client := http.Client{
		Transport: &http.Transport{
			TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
		},
	}
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}

	req.Header.Set("X-Requested-With", "curl")
	// 可选:显式设置和curl一致的User-Agent,避免被WAF规则拦截
	req.Header.Set("User-Agent", "curl/7.68.0")
	req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("asdf:asdfas")))

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(string(body))
}

补充排查点

如果上述修改后仍报错,可通过tcpdump/Wireshark抓包对比curl、Python请求和Golang请求的差异,重点对齐以下配置:

  • TLS握手阶段的加密套件(Cipher Suites)列表,确保和正常请求使用的套件匹配
  • 请求头的Accept、Accept-Encoding字段,和正常请求保持一致
  • 禁用TCP自动窗口缩放、TCP快速打开等可能被网关异常拦截的TCP特性

内容的提问来源于stack exchange,提问作者Xiaorong Liao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 03:24:16