c# 如何进行http请求

来源:这里教程网 时间:2026-02-21 17:38:59 作者:

HttpClient
发起最简 GET 请求

绝大多数场景下,直接用

HttpClient
就够了,它线程安全、支持连接池、能复用底层 TCP 连接。别每次请求都 new 一个实例——这是最常见的内存泄漏和 socket 耗尽源头。

正确做法是全局复用单个

HttpClient
实例(比如声明为
static readonly
或注入到 DI 容器):

private static readonly HttpClient _client = new HttpClient();
public async Task<string> GetContentAsync(string url)
{
    var response = await _client.GetAsync(url);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

注意:

EnsureSuccessStatusCode()
会在 HTTP 状态码非 2xx 时抛出
HttpRequestException
,避免手动检查
response.IsSuccessStatusCode

POST JSON 数据并读取响应

发 JSON 是高频需求,关键在设置正确的

Content-Type
和序列化方式。.NET 6+ 推荐用
System.Text.Json
,轻量且无额外依赖。

HttpClient
默认不带 JSON 支持,需手动序列化 + 设置
StringContent
别用
application/json; charset=utf-8
——
charset
在 JSON 媒体类型中是冗余且可能被某些服务拒绝的
响应体同样建议用
ReadAsStringAsync()
ReadAsByteArrayAsync()
,避免阻塞线程
var data = new { Name = "Alice", Age = 30 };
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync("https://api.example.com/users", content);
var result = await response.Content.ReadAsStringAsync();

处理超时、重试和取消

生产环境必须控制请求生命周期。

HttpClient
Timeout
属性只作用于单次请求(包括 DNS 解析、连接、发送、接收),不适用于整个异步操作链;更灵活的方式是传入
CancellationToken

TimeSpan.FromSeconds(10)
创建 token:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
cts.Token
传给所有
GetAsync
/
PostAsync
调用
如需自动重试,不要手写 while 循环——引入
Polly
库更可靠,尤其配合指数退避
注意:
CancellationToken
取消后,
HttpClient
不会主动中断底层 socket,但会尽快退出等待并抛出
OperationCanceledException

绕过 SSL 证书验证(仅限测试)

开发时遇到自签名证书报错

AuthenticationException: The remote certificate is invalid
,临时方案是配置
HttpClientHandler
ServerCertificateCustomValidationCallback

var handler = new HttpClientHandler
{
    ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};
var client = new HttpClient(handler);

这个回调返回

true
表示信任所有证书——上线前必须删掉,且不能用于任何生产或用户数据场景。真实项目应通过添加根证书或使用正式签发的域名证书解决。

真正容易被忽略的是:一旦用了自定义

HttpClientHandler
,你就得自己管理它的生命周期;如果 handler 含有 unmanaged 资源(比如自定义 DNS 解析逻辑),没正确 dispose 会导致句柄泄露。

相关推荐