跳转到内容

C Sharp HTTP 客户端

来自代码酷

C# HTTP客户端[编辑 | 编辑源代码]

HTTP客户端是C#网络编程中用于发送HTTP请求和接收HTTP响应的核心组件。.NET框架提供了多种方式来实现HTTP通信,包括传统的HttpWebRequestWebClient,以及现代推荐的HttpClient类。本章将重点介绍这些技术的使用方法、最佳实践和实际应用场景。

概述[编辑 | 编辑源代码]

HTTP客户端允许应用程序与Web服务器进行通信,发送请求(如GET、POST等)并处理响应。在C#中,主要使用以下类:

  • HttpWebRequest:早期的底层HTTP客户端实现
  • WebClient:更高级别的封装,简化常见操作
  • HttpClient:.NET 4.5+引入的现代HTTP客户端,支持异步操作

随着.NET的发展,HttpClient已成为推荐选择,因为它:

  • 支持异步编程模型
  • 可重用连接(减少资源消耗)
  • 更灵活的请求/响应处理
  • 更好的性能

HttpClient 基础[编辑 | 编辑源代码]

HttpClient位于System.Net.Http命名空间,是处理HTTP请求的主要类。

基本用法[编辑 | 编辑源代码]

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // 创建HttpClient实例
        using HttpClient client = new HttpClient();
        
        // 发送GET请求
        HttpResponseMessage response = await client.GetAsync("https://api.example.com/data");
        
        // 确保请求成功
        response.EnsureSuccessStatusCode();
        
        // 读取响应内容
        string responseBody = await response.Content.ReadAsStringAsync();
        
        Console.WriteLine(responseBody);
    }
}

输出示例

{
    "userId": 1,
    "id": 1,
    "title": "示例数据",
    "completed": false
}

关键组件[编辑 | 编辑源代码]

  • HttpClient:发送请求和接收响应的主类
  • HttpRequestMessage:表示HTTP请求消息
  • HttpResponseMessage:表示HTTP响应消息
  • HttpContent:表示HTTP内容(请求体或响应体)

高级特性[编辑 | 编辑源代码]

自定义请求头[编辑 | 编辑源代码]

using (HttpClient client = new HttpClient())
{
    // 添加自定义请求头
    client.DefaultRequestHeaders.Add("User-Agent", "MyApp/1.0");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
    // 添加授权头
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "your_token_here");
    
    var response = await client.GetAsync("https://api.example.com/protected");
    // 处理响应...
}

POST请求与JSON内容[编辑 | 编辑源代码]

var user = new { Name = "John", Age = 30 };
string json = JsonSerializer.Serialize(user);

using (var content = new StringContent(json, Encoding.UTF8, "application/json"))
using (HttpClient client = new HttpClient())
{
    var response = await client.PostAsync("https://api.example.com/users", content);
    
    if (response.IsSuccessStatusCode)
    {
        var responseJson = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"服务器响应: {responseJson}");
    }
}

处理不同响应类型[编辑 | 编辑源代码]

// 处理JSON响应
var response = await client.GetAsync("https://api.example.com/data");
if (response.IsSuccessStatusCode)
{
    var data = await response.Content.ReadFromJsonAsync<MyDataClass>();
    Console.WriteLine($"Received: {data}");
}

// 处理二进制数据
var imageResponse = await client.GetAsync("https://example.com/image.png");
if (imageResponse.IsSuccessStatusCode)
{
    byte[] imageData = await imageResponse.Content.ReadAsByteArrayAsync();
    File.WriteAllBytes("downloaded.png", imageData);
}

最佳实践[编辑 | 编辑源代码]

HttpClient生命周期管理[编辑 | 编辑源代码]

HttpClient设计为可重用,不应为每个请求创建新实例。最佳实践包括:

  • 在应用程序生命周期内重用单个HttpClient实例
  • 或使用IHttpClientFactory(在ASP.NET Core中)

超时设置[编辑 | 编辑源代码]

var client = new HttpClient
{
    Timeout = TimeSpan.FromSeconds(30) // 设置30秒超时
};

取消支持[编辑 | 编辑源代码]

var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(10)); // 10秒后取消

try
{
    var response = await client.GetAsync("https://slow-api.example.com", cts.Token);
    // 处理响应...
}
catch (TaskCanceledException)
{
    Console.WriteLine("请求已取消");
}

实际应用案例[编辑 | 编辑源代码]

天气API客户端[编辑 | 编辑源代码]

public class WeatherService
{
    private readonly HttpClient _httpClient;
    
    public WeatherService(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri("https://api.weatherapi.com/v1/");
    }
    
    public async Task<WeatherData> GetCurrentWeatherAsync(string location)
    {
        var response = await _httpClient.GetAsync($"current.json?key=YOUR_API_KEY&q={location}");
        response.EnsureSuccessStatusCode();
        
        return await response.Content.ReadFromJsonAsync<WeatherData>();
    }
}

// 使用示例
var weatherService = new WeatherService(new HttpClient());
var weather = await weatherService.GetCurrentWeatherAsync("London");
Console.WriteLine($"当前温度: {weather.Current.TempC}°C");

文件下载进度报告[编辑 | 编辑源代码]

public async Task DownloadFileWithProgressAsync(string fileUrl, string localPath, IProgress<double> progress)
{
    using (var client = new HttpClient())
    {
        // 只获取头部信息来确定内容长度
        using (var response = await client.GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead))
        {
            response.EnsureSuccessStatusCode();
            
            var totalBytes = response.Content.Headers.ContentLength ?? -1L;
            var receivedBytes = 0L;
            
            using (var contentStream = await response.Content.ReadAsStreamAsync())
            using (var fileStream = new FileStream(localPath, FileMode.Create))
            {
                var buffer = new byte[8192];
                var isMoreToRead = true;
                
                do
                {
                    var read = await contentStream.ReadAsync(buffer, 0, buffer.Length);
                    if (read == 0)
                    {
                        isMoreToRead = false;
                    }
                    else
                    {
                        await fileStream.WriteAsync(buffer, 0, read);
                        
                        receivedBytes += read;
                        if (totalBytes > 0)
                        {
                            progress.Report((double)receivedBytes / totalBytes);
                        }
                    }
                }
                while (isMoreToRead);
            }
        }
    }
}

// 使用示例
var progress = new Progress<double>(p => Console.WriteLine($"下载进度: {p:P}"));
await DownloadFileWithProgressAsync("https://example.com/largefile.zip", "largefile.zip", progress);

性能考虑[编辑 | 编辑源代码]

连接池[编辑 | 编辑源代码]

HttpClient内部使用连接池来重用HTTP连接。可以通过ServicePointManager进行配置:

ServicePointManager.DefaultConnectionLimit = 20; // 增加默认连接限制

HTTP/2 支持[编辑 | 编辑源代码]

从.NET Core 3.0开始,HttpClient支持HTTP/2协议:

var client = new HttpClient()
{
    DefaultRequestVersion = HttpVersion.Version20
};

常见问题与解决方案[编辑 | 编辑源代码]

问题 解决方案
Socket耗尽 重用HttpClient实例或使用IHttpClientFactory
DNS变更不生效 设置HttpClient的BaseAddress或使用HttpClientHandler的PooledConnectionLifetime
大文件下载内存问题 使用流式处理(ReadAsStreamAsync)而非缓冲(ReadAsByteArrayAsync)
SSL/TLS错误 配置正确的SecurityProtocol或处理证书验证

总结[编辑 | 编辑源代码]

C#中的HTTP客户端功能强大且灵活,从简单的GET请求到复杂的API交互都能胜任。现代应用程序应优先使用HttpClient类,遵循最佳实践来确保性能、可靠性和安全性。通过合理配置和错误处理,可以构建健壮的HTTP通信组件,满足各种网络编程需求。