C# HttpClient完整使用指南

1. 前言

在现代应用程序开发中,与Web服务进行HTTP通信是一项基本需求。C#中的HttpClient类为开发者提供了强大而灵活的HTTP客户端功能。本教程将全面讲解如何在C#中使用HttpClient,包括基本用法、高级配置、最佳实践以及常见问题的解决方案。

2. HttpClient 简介

2.1 什么是HttpClient

HttpClient是.NET Framework 4.5+和.NET Core/.NET 5+中引入的一个类,位于System.Net.Http命名空间下,用于发送HTTP请求和接收HTTP响应。它取代了旧的WebClientHttpWebRequest类,提供了更现代、更灵活的API。

2.2 主要特性

  • 支持异步操作
  • 可扩展的消息处理管道
  • 支持HTTP/1.1和HTTP/2
  • 内置连接池管理
  • 支持多种认证方式
  • 可配置的超时和重试策略

3. 基本用法

3.1 创建HttpClient实例

cs 复制代码
using System.Net.Http;

// 最简单的创建方式
var httpClient = new HttpClient();

3.2 发送GET请求

cs 复制代码
// 异步GET请求
public async Task<string> GetDataAsync(string url)
{
    try
    {
        HttpResponseMessage response = await httpClient.GetAsync(url);
        response.EnsureSuccessStatusCode(); // 确保响应成功
        return await response.Content.ReadAsStringAsync();
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"请求失败: {ex.Message}");
        return null;
    }
}

3.3 发送POST请求

cs 复制代码
public async Task<string> PostDataAsync(string url, string jsonContent)
{
    try
    {
        var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
        HttpResponseMessage response = await httpClient.PostAsync(url, content);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"请求失败: {ex.Message}");
        return null;
    }
}

4. 高级配置

4.1 自定义请求头

cs 复制代码
httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

4.2 设置超时

cs 复制代码
httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置30秒超时

4.3 处理不同响应类型

cs 复制代码
public async Task<T> GetJsonAsync<T>(string url)
{
    var response = await httpClient.GetAsync(url);
    response.EnsureSuccessStatusCode();
    var jsonString = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<T>(jsonString);
}

5. HttpClientFactory 最佳实践

直接实例化HttpClient可能导致套接字耗尽等问题。推荐使用HttpClientFactory

5.1 在ASP.NET Core中使用

cs 复制代码
// 在Startup.cs中注册
services.AddHttpClient();

// 在控制器中注入
public class MyController : Controller
{
    private readonly IHttpClientFactory _clientFactory;
    
    public MyController(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }
    
    public async Task<IActionResult> GetData()
    {
        var client = _clientFactory.CreateClient();
        // 使用client...
    }
}

5.2 命名客户端

cs 复制代码
// 注册命名客户端
services.AddHttpClient("GitHubClient", client =>
{
    client.BaseAddress = new Uri("https://api.github.com/");
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
    client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});

// 使用命名客户端
var client = _clientFactory.CreateClient("GitHubClient");

6. 处理异常和重试

6.1 使用Polly实现重试策略

cs 复制代码
services.AddHttpClient("RetryClient")
    .AddTransientHttpErrorPolicy(policy => 
        policy.WaitAndRetryAsync(new[]
        {
            TimeSpan.FromSeconds(1),
            TimeSpan.FromSeconds(5),
            TimeSpan.FromSeconds(10)
        }));

6.2 自定义异常处理

cs 复制代码
public async Task<HttpResponseMessage> SendRequestWithRetryAsync(Func<Task<HttpResponseMessage>> request)
{
    int retryCount = 0;
    while (true)
    {
        try
        {
            var response = await request();
            if (response.IsSuccessStatusCode || retryCount >= 3)
                return response;
        }
        catch (HttpRequestException) when (retryCount < 3)
        {
            // 记录日志
        }
        
        retryCount++;
        await Task.Delay(1000 * retryCount);
    }
}

7. 性能优化

7.1 连接池管理

cs 复制代码
// 在应用启动时配置
var socketsHandler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(10), // 连接存活时间
    PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5), // 空闲连接超时
    MaxConnectionsPerServer = 50 // 每个服务器的最大连接数
};

var httpClient = new HttpClient(socketsHandler);

7.2 使用HttpCompletionOption

cs 复制代码
// 只读取头部而不缓冲内容
var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);

8. 安全考虑

8.1 处理HTTPS证书

cs 复制代码
var handler = new HttpClientHandler
{
    ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => 
    {
        // 自定义证书验证逻辑
        return errors == System.Net.Security.SslPolicyErrors.None;
    }
};

var httpClient = new HttpClient(handler);

8.2 认证和授权

cs 复制代码
// 基本认证
var byteArray = Encoding.ASCII.GetBytes("username:password");
httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

// Bearer Token
httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", "your_access_token");

9. 常见问题与解决方案

9.1 套接字耗尽

问题 : 频繁创建和销毁HttpClient实例会导致套接字耗尽。

解决方案 : 使用HttpClientFactory或单例模式管理HttpClient实例。

9.2 超时设置

问题: 请求因网络问题长时间挂起。

解决方案 : 合理设置Timeout属性,并实现重试机制。

9.3 内容序列化

问题: 处理效率低下。

解决方案 : 使用System.Text.Json进行高效序列化:

cs 复制代码
var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    WriteIndented = true
};

var json = JsonSerializer.Serialize(data, options);
var data = JsonSerializer.Deserialize<MyType>(json, options);

10. 实际案例

10.1 调用REST API

cs 复制代码
public class GitHubService
{
    private readonly HttpClient _httpClient;
    
    public GitHubService(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri("https://api.github.com/");
        _httpClient.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
        _httpClient.DefaultRequestHeaders.Add("User-Agent", "GitHub-API-Client");
    }
    
    public async Task<List<GitHubRepo>> GetRepositoriesAsync(string username)
    {
        var response = await _httpClient.GetAsync($"/users/{username}/repos");
        response.EnsureSuccessStatusCode();
        
        using var responseStream = await response.Content.ReadAsStreamAsync();
        return await JsonSerializer.DeserializeAsync<List<GitHubRepo>>(responseStream);
    }
}

10.2 文件上传

cs 复制代码
public async Task UploadFileAsync(string url, string filePath)
{
    using var fileStream = File.OpenRead(filePath);
    using var content = new StreamContent(fileStream);
    using var formData = new MultipartFormDataContent
    {
        { content, "file", Path.GetFileName(filePath) }
    };
    
    var response = await _httpClient.PostAsync(url, formData);
    response.EnsureSuccessStatusCode();
}

11. 总结

HttpClient是C#中进行HTTP通信的强大工具,但需要正确使用以避免常见陷阱。关键要点包括:

  1. 使用HttpClientFactory管理HttpClient生命周期
  2. 合理配置超时和重试策略
  3. 正确处理异常和错误响应
  4. 优化性能和安全配置
  5. 根据场景选择合适的序列化方式
相关推荐
JaydenAI1 小时前
[MAF预定义的AIContextProvider-02]AgentSkillsProvider——将Agent Skills引入MAF
ai·c#·agent·agent skills·maf
小满Autumn2 小时前
MVVM Light 架构笔记:定位器、命令、消息与 IoC 实践
笔记·学习·架构·c#·上位机·mvvm
小满Autumn3 小时前
CommunityToolkit.Mvvm 架构笔记:现代 MVVM、源生成器与工程化实践
笔记·架构·c#·.net·wpf·mvvm
加号34 小时前
【C#】 JSON 序列化与反序列化:从入门到最佳实践
c#·json
胖纸不争8 小时前
自建 Copilot Cli 代理:让 GitHub Copilot 真正"Bring Your Own Key"
ai·c#
FuckPatience10 小时前
C# new List<T>(IEnumerable<T> collection),链表初始化时传入已存在链表
链表·c#·list
专注VB编程开发20年12 小时前
工控上位机开发为什么固死.net 4.5.2sdk?适配win7
python·信息可视化·c#
狂人开飞机14 小时前
18. 中介者模式(Mediator Pattern)
设计模式·c#·中介者模式
victory_li14 小时前
OpenVINO + Yolov26 + C# + .net framework4.8实现分类推理
yolo·c#·openvino