C# HttpClient 网络请求

2 min入门

C# HttpClient 网络请求 的完整教学讲解。

HttpClient 基础

基本写法:创建 HttpClient HttpClient <变量> = new();

// 单例复用,避免套接字耗尽
private static readonly HttpClient _client = new();

基本写法:GET 字符串 await <client>.GetStringAsync(<url>);

// 直接获取响应文本
string body = await _client.GetStringAsync("https://api.example.com/users");

基本写法:GET 字节数组 await <client>.GetByteArrayAsync(<url>);

// 获取二进制内容
byte[] bytes = await _client.GetByteArrayAsync("https://a.com/img.png");

基本写法:GET 流 await <client>.GetStreamAsync(<url>);

// 获取响应流,适合大文件
using Stream s = await _client.GetStreamAsync(url);

基本写法:HttpClientFactory 注册 services.AddHttpClient();

// ASP.NET Core 中使用工厂管理生命周期
builder.Services.AddHttpClient();

基本请求响应

基本写法:发送 GET 请求 await <client>.GetAsync(<url>);

// 获取完整响应对象
using var resp = await _client.GetAsync(url);
resp.EnsureSuccessStatusCode();

基本写法:读取响应内容 await <响应>.Content.ReadAsStringAsync();

// 读取响应体字符串
var resp = await _client.GetAsync(url);
string body = await resp.Content.ReadAsStringAsync();

基本写法:POST 字符串 await <client>.PostAsync(<url>, <内容>);

// 提交字符串内容
var content = new StringContent("raw body", Encoding.UTF8, "text/plain");
await _client.PostAsync(url, content);

基本写法:POST JSON JsonContent.Create(<对象>);

// .NET 5+ 直接创建 JSON 内容
var json = JsonContent.Create(user);
await _client.PostAsync(url, json);

基本写法:POST 表单 new FormUrlEncodedContent(<字典>);

// 提交 application/x-www-form-urlencoded
var form = new FormUrlEncodedContent(new[]
{
    new KeyValuePair<string, string>("name", "Alice")
});
await _client.PostAsync(url, form);

HttpRequestMessage 自定义

基本写法:构造请求消息 new HttpRequestMessage(<方法>, <url>);

// 完全自定义请求
var req = new HttpRequestMessage(HttpMethod.Post, url);
req.Content = json;
var resp = await _client.SendAsync(req);

基本写法:自定义方法 new HttpMethod("<方法名>")

// 使用 PATCH 等非标准方法
var req = new HttpRequestMessage(new HttpMethod("PATCH"), url);

基本写法:添加请求头 <请求>.Headers.Add("<名称>", "<值>");

// 设置请求头
req.Headers.Add("Authorization", "Bearer token123");
req.Headers.Add("X-Request-Id", Guid.NewGuid().ToString());

基本写法:默认请求头 <client>.DefaultRequestHeaders.Add("<名称>", "<值>");

// 所有请求都带上的头
_client.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");

基本写法:超时设置 <client>.Timeout = <时间>;

// 设置全局超时
_client.Timeout = TimeSpan.FromSeconds(30);

响应处理

基本写法:读取响应头 <响应>.Headers.<名称>

// 获取响应头
foreach (var h in resp.Headers)
{
    Console.WriteLine($"{h.Key}: {string.Join(",", h.Value)}");
}

基本写法:获取状态码 <响应>.StatusCode

// 读取 HTTP 状态码
HttpStatusCode code = resp.StatusCode;
if (code == HttpStatusCode.OK) { }

基本写法:反序列化 JSON 响应 await JsonSerializer.DeserializeAsync<<类型>>(<流>);

// 流式反序列化响应
var resp = await _client.GetAsync(url);
var user = await JsonSerializer.DeserializeAsync<User>(
    await resp.Content.ReadAsStreamAsync());

取消与进度

基本写法:取消请求 await <client>.GetAsync(<url>, <token>);

// 传入取消令牌
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var resp = await _client.GetAsync(url, cts.Token);

基本写法:HttpCompletionOption await <client>.GetAsync(<url>, HttpCompletionOption.ResponseHeadersRead);

// 收到响应头即返回,不等读完体
var resp = await _client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);

基本写法:上传进度 <流>.ReadAsync(<缓冲>, <token>)

// 自定义 HttpContent 实现上传进度
public class ProgressContent : HttpContent { /* 重写 SerializeToStreamAsync */ }

上传文件

基本写法:Multipart 表单 MultipartFormDataContent <变量> = new();

// multipart/form-data 上传文件
using var form = new MultipartFormDataContent();
var fileContent = new ByteArrayContent(File.ReadAllBytes(path));
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
form.Add(fileContent, "file", "photo.png");
await _client.PostAsync(url, form);

基本写法:流式上传 new StreamContent(<流>);

// 大文件用流避免全加载到内存
using var fs = File.OpenRead("big.zip");
var form = new MultipartFormDataContent();
form.Add(new StreamContent(fs), "file", "big.zip");
await _client.PostAsync(url, form);

复用与命名客户端

基本写法:命名客户端 services.AddHttpClient("<名称>", <配置>);

// 注册预配置的命名 HttpClient
builder.Services.AddHttpClient("github", c =>
{
    c.BaseAddress = new Uri("https://api.github.com/");
    c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
});

基本写法:注入命名客户端 IHttpClientFactory <变量>

// 通过工厂获取命名客户端
public class Service(IHttpClientFactory factory)
{
    public async Task DoAsync()
    {
        var client = factory.CreateClient("github");
        var json = await client.GetStringAsync("users/octocat");
    }
}

基本写法:类型化客户端 services.AddHttpClient<<类型>>();

// 直接绑定到某服务类
builder.Services.AddHttpClient<GitHubService>(c => c.BaseAddress = new Uri("https://api.github.com/"));

BaseAddress 与相对路径

基本写法:设置基地址 <client>.BaseAddress = new Uri(<url>);

// 设置基地址后用相对路径
_client.BaseAddress = new Uri("https://api.example.com/");
var json = await _client.GetStringAsync("users/1");

重试与弹性

基本写法:Polly 重试 services.AddHttpClient("<名称>").AddTransientHttpErrorPolicy(...)

// 使用 Polly 实现重试
builder.Services.AddHttpClient("api")
    .AddTransientHttpErrorPolicy(p =>
        p.WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(i)));

基本写法:超时策略 .AddPolicyHandler(Policy.TimeoutAsync<<HttpResponseMessage>>(<秒>))

// 每个请求的超时策略
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(20)));

基本写法:处理 Cookie new HttpClient(new HttpClientHandler { UseCookies = true })

// 启用 Cookie 容器
var handler = new HttpClientHandler { UseCookies = true, CookieContainer = new CookieContainer() };
var client = new HttpClient(handler);

基本写法:设置代理 new HttpClientHandler { Proxy = <代理> }

// 通过代理访问
var handler = new HttpClientHandler
{
    Proxy = new WebProxy("http://proxy:8080", true)
};
var client = new HttpClient(handler);

SocketsHttpHandler 配置

基本写法:自定义连接池 new SocketsHttpHandler { PooledConnectionLifetime = <时间> }

// .NET Core 2.1+ 默认使用 SocketsHttpHandler
var handler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(2),
    MaxConnectionsPerServer = 100
};
var client = new HttpClient(handler);