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

Go net/http POST请求遇wsarecv错误:远程主机强制关闭连接求助

Go net/http POST请求获取AccessToken时遭遇连接被远程强制关闭的问题

我用Go的net/http包发送POST请求获取access token时,遇到错误:

Post "https://some.url.gov.ss/tgd/STS/oauth2/token": read tcp 123.123.104.104:53387->123.123.153.251:443: wsarecv: An existing connection was forcibly closed by the remote host

诡异的是,用Python aiohttp请求这个特定URL完全正常,而且相同的Go代码请求其他URL也没问题。我查了大部分wsarecv相关的解决方案都没用,参照API提供方的PHP示例关闭了SSL验证也没解决。

我的Go代码(main.go)

type JSONcontent interface{}

var (
    transport = &http.Transport{
        TLSClientConfig: &tls.Config{
            InsecureSkipVerify: true,
        },
    }
    client      = &http.Client{Transport: transport}
    vissPayload VISSPayload
    results     JSONcontent
)

func requestAccessToken(token string, vissPayload VISSPayload) error {
    data := url.Values{}
    data.Add("grant_type", "client_credentials")
    data.Add("client_id", vissPayload.CERT_CLIENT_ID)
    data.Add("client_secret", vissPayload.CERT_CLIENT_SECRET)
    data.Add("client_assertion_type", vissPayload.CERT_CLIENT_ASSERTION_TYPE)
    data.Add("client_assertion", token)

    request, err := http.NewRequest(http.MethodPost, vissPayload.CERT_TOKEN_URL, bytes.NewBufferString(data.Encode()))
    if err != nil {
        return fmt.Errorf("request error: %v", err)
    }

    request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    request.Header.Add("Accept", "application/json")
    request.Header.Add("Cache-Control", "no-cache")

    response, err := client.Do(request)
    if err != nil {
        return fmt.Errorf("request failed error: %v", err)
    }
    defer response.Body.Close()

    body, err := io.ReadAll(request.Body)
    if err != nil {
        return fmt.Errorf("failed ot read body error: %v", err)
    }

    if err := json.Unmarshal(body, &results); err != nil {
        return fmt.Errorf("failed to unmarshal body error: %v", err)
    }

    return nil
}

API提供方的PHP示例(index.php,未本地测试)

function getAccessTokenWithSertificate(){

    ... CERT stuff processing ...

    //Configuring URL & SSL
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, self::CERTIFICATE_TOKEN_URL);

    //Turn off all TLS security issues
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLINFO_HEADER_OUT, true);

    //Return result in string
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    //Configuring headers
    $headers = array(
        "cache-control: no-cache",
        "Accept: application/json"
    );

    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

    //Configuring post request
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, [
        "grant_type" => "client_credentials",
        "client_assertion_type" => "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_secret" => self::CERTIFICATE_CLIENT_SECRET,
        "client_id" => self::CERTIFICATE_CLIENT_ID,
        "client_assertion" => $jwt,
        "scope" => self::CERTIFICATE_SCOPE
    ]);

    //Getting result
    $result = curl_exec($curl);
    $json = json_decode($result, true);
    curl_close($curl);

    return $json["access_token"];
}

可正常运行的Python aiohttp示例(main.py)

async def test_request_access_token(self) -> None:

    ... CERT stuff processing ...
    
    # Request access token
    request_headers = {
        "cache-control": "no-cache",
        "Accept": "application/json",
    }

    # Set request payload
    request_payload = {
        "grant_type": "client_credentials",
        "client_id": client_id,
        "client_secret": client_secret,
        "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        "client_assertion": JWT,
    }

    # Execute async POST request
    # Trace request
    trace_config = aiohttp.TraceConfig()
    trace_config.on_request_start.append(on_request_start)
    trace_config.on_request_end.append(on_request_end)

    async with aiohttp.ClientSession(trace_configs=[trace_config]) as session:
        async with session.post(
            certificate_token_url,
            data=request_payload,
            headers=request_headers,
        ) as response:
            payload: dict = await response.json()
            print("Request date: %s" % response.headers.get("Date"))

            if response.status != 200:
                print(f"Error: request returned: {response.status}")
                for key in payload.keys():
                    print(f"{key}: {payload[key]}")
            else:
                for key in payload.keys():
                    print(f"{key}: {payload[key]}")
                self.access_token = payload["access_token"]

可能的解决方案

1. 修复请求体读取错误

代码里犯了低级错误:读取的是request.Body而非response.Body,这会导致读取空内容甚至影响连接状态。修改为:

body, err := io.ReadAll(response.Body)

2. 强制指定TLS版本

部分服务器仅支持特定TLS版本(如TLS 1.2),Go默认尝试最高版本可能不兼容。强制指定版本:

transport = &http.Transport{
    TLSClientConfig: &tls.Config{
        InsecureSkipVerify: true,
        MinVersion: tls.VersionTLS12,
        MaxVersion: tls.VersionTLS12,
    },
}

3. 禁用HTTP/2强制使用HTTP/1.1

部分服务器对HTTP/2支持不佳,Go默认启用HTTP/2,可强制切换:

transport = &http.Transport{
    TLSClientConfig: &tls.Config{
        InsecureSkipVerify: true,
    },
    ForceAttemptHTTP2: false,
}

4. 统一请求头大小写

虽然HTTP头大小写不敏感,但部分服务器可能有严格要求,将请求头改为小写与其他示例保持一致:

request.Header.Add("content-type", "application/x-www-form-urlencoded")
request.Header.Add("accept", "application/json")
request.Header.Add("cache-control", "no-cache")

5. 添加缺失的scope参数

对比PHP示例,你的Go代码未传递scope参数,若API要求必填则需补充:

data.Add("scope", vissPayload.CERT_SCOPE)

6. 启用TLS握手日志排查

开启日志查看TLS握手细节,定位版本或套件兼容性问题:

import "log"

// 初始化transport前添加日志配置
log.SetFlags(log.LstdFlags | log.Lshortfile)
transport.TLSClientConfig.VerifyConnection = func(cs tls.ConnectionState) error {
    log.Printf("TLS Version: %s", cs.Version.String())
    log.Printf("Cipher Suite: %s", cs.CipherSuite.String())
    log.Printf("Server Name: %s", cs.ServerName)
    return nil
}

内容的提问来源于stack exchange,提问作者Reinis Gaņģis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:55:57