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

C# HttpClient在Linux VPS请求超时(ping、curl正常无防火墙)

问题描述

我希望通过HttpClient获取页面内容,编写了如下简单方法,该方法在Visual Studio中运行正常。

private async Task<string> Connection(string Url)
{
    using HttpClient client = new();
    client.DefaultRequestHeaders.Add("Accept", "application/json");
    client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 OPR/77.0.4054.277");
    client.DefaultRequestHeaders.Add("Cache-Control", "no-cache, no-store, must-revalidate");
    client.DefaultRequestHeaders.Add("Accept-Language", "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7");
    client.DefaultRequestHeaders.Add("Pragma", "no-cache");

    double timestamp = GlobalMethod.Timestamp();
    string json = await client.GetStringAsync(Url);
    return json;
}

但当我在OVH托管的Ubuntu Linux VPS上运行应用(运行环境为.NET 5)时,HttpClient返回超时错误。
该VPS上ping目标地址、使用curl请求均正常,Postman使用相同参数请求也无问题,不存在防火墙拦截。
API链接:https://api.store.nvidia.com/partner/v1/feinventory?skus=FRNVGFT070NVGFT080NVGFT090NVLKR30SNSHRMT01NVGFT060T~187&locale=FR
超时错误信息如下:

System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing.
---> System.TimeoutException: The operation was canceled.
---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
---> System.IO.IOException: Unable to read data from the transport connection: Operation canceled.
---> System.Net.Sockets.SocketException (125): Operation canceled
--- End of inner exception stack trace ---
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 token)
at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
at System.Net.Http.HttpConnection.FillAsync(Boolean async)
at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean async, Boolean foldedHeadersAllowed)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.GetStringAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at Castiel_Bot_Discord.Modules.NvidiaCommand.Connection(String Url) in C:\Users\gaeta\source\repos\Castiel_Bot_Discord\Castiel_Bot_Discord\Modules\NvidiaCommand.cs:line 114
at Castiel_Bot_Discord.Modules.NvidiaCommand.SearchGpu(String args) in C:\Users\gaeta\source\repos\Castiel_Bot_Discord\Castiel_Bot_Discord\Modules\NvidiaCommand.cs:line 42


解决方案

问题根因

该问题是.NET 5在Linux环境下的HttpClient默认配置和Windows环境存在差异导致,核心触发点通常为以下两个:

  1. IPv6优先解析但VPS到目标API的IPv6链路不通,.NET 5的HttpClient默认不会自动降级到IPv4,而curl会自动尝试双栈并降级
  2. TLS版本/加密套件协商规则和curl不同,nvidia的API服务器拒绝了.NET发出的TLS握手请求

修复步骤

1. 调整HttpClient配置,强制使用IPv4+指定TLS版本

修改你的Connection方法,自定义HttpClientHandler替换默认配置,同时建议将HttpClient改为单例避免端口耗尽问题:
以下代码需要引入System.Net.Sockets、System.Net.Security、System.Security.Authentication命名空间

private static readonly HttpClient _client = new HttpClient(new SocketsHttpHandler
{
    // 强制使用IPv4解析
    ConnectCallback = async (context, cancellationToken) =>
    {
        var entry = await Dns.GetHostEntryAsync(context.DnsEndPoint.Host, AddressFamily.InterNetwork, cancellationToken);
        var address = entry.AddressList[0];
        var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
        {
            NoDelay = true
        };
        try
        {
            await socket.ConnectAsync(address, context.DnsEndPoint.Port, cancellationToken);
            return new NetworkStream(socket, ownsSocket: true);
        }
        catch
        {
            socket.Dispose();
            throw;
        }
    },
    // 限定支持的TLS版本
    SslOptions = new SslClientAuthenticationOptions
    {
        EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13
    }
})
{
    Timeout = TimeSpan.FromSeconds(30)
};

private async Task<string> Connection(string Url)
{
    _client.DefaultRequestHeaders.Clear();
    _client.DefaultRequestHeaders.Add("Accept", "application/json");
    _client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 OPR/77.0.4054.277");
    _client.DefaultRequestHeaders.Add("Cache-Control", "no-cache, no-store, must-revalidate");
    _client.DefaultRequestHeaders.Add("Accept-Language", "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7");
    _client.DefaultRequestHeaders.Add("Pragma", "no-cache");

    string json = await _client.GetStringAsync(Url);
    return json;
}

2. 快速验证方案

如果不想先改代码,可以直接在VPS系统层面临时禁用IPv6验证根因:

sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1

如果禁用后请求正常,即可确认是IPv6解析导致的问题。

3. 长期优化建议

.NET 5已经停止官方支持,建议升级到.NET 6+,新版本的HttpClient已经优化了双栈解析的降级逻辑,默认行为和curl保持一致,可避免同类问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 00:06:04