VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • C#网格编程之HTTP编程(HttpClient、HttpListener)

第6章 C# HTTP编程实战
6.1 C# HTTP编程(HttpClient、HttpListener)
一、为什么要学这两个类?
我刚做C# HTTP开发时,只会用HttpClient发请求,直到需要写一个轻量级HTTP服务器,才发现HttpListener的好用——不需要搭ASP.NET Core,几行代码就能写一个能处理请求的服务器。后来又踩了HttpClient的坑:每次请求都创建新实例,导致系统端口耗尽,程序崩溃。这节我把自己踩过的坑、实战经验都揉vb.net教程C#教程python教程SQL教程access 2010教程
进去,用大白话讲透HttpClient和HttpListener的用法,结合代码逐行讲解,让你既能高效发HTTP请求,又能快速写HTTP服务器。
二、HttpClient:C#发HTTP请求的“瑞士军刀”
HttpClient是.NET官方封装的HTTP客户端,不管是GET、POST、PUT、DELETE,还是HTTPS、CORS、代理,它都能搞定——就像你用手机浏览器上网,不需要懂HTTP协议的细节,直接输入网址就行。

  1. 先搞懂HttpClient的核心坑:不要每次请求都创建!
    我刚学HttpClient时,每次请求都new HttpClient(),结果程序跑了几个小时就崩溃了——后来才知道:HttpClient会创建底层的HttpMessageHandler,而HttpMessageHandler会占用系统端口,每次创建HttpClient都会新建一个HttpMessageHandler,导致端口耗尽。
    正确做法:全局单例HttpClient,或者用IHttpClientFactory(推荐)。
    错误示例:
    csharp
	// 错误:每次请求都创建HttpClient,会耗尽端口
	foreach (var url in urls)
	{
	using var httpClient = new HttpClient();
	var response = await httpClient.GetAsync(url);
	}

正确示例(全局单例):
csharp

	// 正确:全局单例HttpClient,整个程序只创建一次
	public static class HttpClientHelper
	{
	public static readonly HttpClient Instance = new HttpClient();
	}
	
	// 用法
	var response = await HttpClientHelper.Instance.GetAsync(url);
  1. C#实战:用HttpClient发送各种HTTP请求
    (1)发送GET请求:获取JSON数据并解析
    csharp
	using System;
	using System.Net.Http;
	using System.Threading.Tasks;
	using System.Text.Json;
	
	namespace HttpClientGetDemo;
	
	class Program
	{
	// 全局单例HttpClient
	private static readonly HttpClient _httpClient = new HttpClient();
	
	static async Task Main(string[] args)
	{
	try
	{
	// 1. 发送GET请求
	string url = "https://jsonplaceholder.typicode.com/users/1";
	HttpResponseMessage response = await _httpClient.GetAsync(url);
	
	// 2. 检查请求是否成功:状态码不是2xx就抛出异常
	response.EnsureSuccessStatusCode();
	
	// 3. 读取响应体:把JSON字符串转换成对象
	string jsonString = await response.Content.ReadAsStringAsync();
	User user = JsonSerializer.Deserialize<User>(jsonString) ?? new User();
	
	// 4. 输出结果
	Console.WriteLine($"用户ID:{user.Id}");
	Console.WriteLine($"用户名:{user.Name}");
	Console.WriteLine($"邮箱:{user.Email}");
	}
	catch (HttpRequestException ex)
	{
	Console.WriteLine($"请求失败:{ex.Message}");
	}
	}
	
	// 定义和JSON对应的实体类
	public class User
	{
	public int Id { get; set; }
	public string Name { get; set; } = string.Empty;
	public string Email { get; set; } = string.Empty;
	}
	}

代码逐行讲:
1.private static readonly HttpClient _httpClient = new HttpClient();:全局单例HttpClient,整个程序只创建一次,避免端口耗尽;
2.await _httpClient.GetAsync(url);:异步发送GET请求,返回HttpResponseMessage,包含状态码、响应头、响应体;
3.response.EnsureSuccessStatusCode();:如果状态码不是2xx(比如404、500),抛出HttpRequestException,方便统一处理错误;
4.await response.Content.ReadAsStringAsync();:读取响应体的字符串内容,response.Content是HttpContent类型,还可以用ReadAsByteArrayAsync()(读取字节数组)、ReadAsStreamAsync()(读取流);
5.JsonSerializer.Deserialize(jsonString);:把JSON字符串转换成User对象,需要引用System.Text.Json包(.NET Core 3.0+自带)。
(2)发送POST请求:提交JSON数据
csharp

	using System;
	using System.Net.Http;
	using System.Net.Http.Json;
	using System.Threading.Tasks;
	
	namespace HttpClientPostDemo;
	
	class Program
	{
	private static readonly HttpClient _httpClient = new HttpClient();
	
	static async Task Main(string[] args)
	{
	try
	{
	// 1. 准备要提交的数据
	var newUser = new User
	{
	Name = "张三",
	Email = "zhangsan@example.com"
	};
	
	// 2. 发送POST请求:自动把对象转换成JSON,设置Content-Type为application/json
	string url = "https://jsonplaceholder.typicode.com/users";
	HttpResponseMessage response = await _httpClient.PostAsJsonAsync(url, newUser);
	
	response.EnsureSuccessStatusCode();
	
	// 3. 读取响应体:获取创建后的用户信息
	User createdUser = await response.Content.ReadFromJsonAsync<User>() ?? new User();
	Console.WriteLine($"创建的用户ID:{createdUser.Id}");
	}
	catch (HttpRequestException ex)
	{
	Console.WriteLine($"请求失败:{ex.Message}");
	}
	}
	
	public class User
	{
	public int Id { get; set; }
	public string Name { get; set; } = string.Empty;
	public string Email { get; set; } = string.Empty;
	}
	}

代码关键:
PostAsJsonAsync(url, newUser):自动把newUser对象序列化成JSON,设置Content-Type为application/json,不需要手动处理JSON序列化;
ReadFromJsonAsync():自动把响应体的JSON反序列化成User对象,简化了代码。
(3)发送PUT请求:更新数据
csharp

	// 准备更新后的数据
	var updatedUser = new User
	{
	Id = 1,
	Name = "李四",
	Email = "lisi@example.com"
	};
	
	// 发送PUT请求
	string url = "https://jsonplaceholder.typicode.com/users/1";
	HttpResponseMessage response = await _httpClient.PutAsJsonAsync(url, updatedUser);
	response.EnsureSuccessStatusCode();

(4)发送DELETE请求:删除数据
csharp

	// 发送DELETE请求
	string url = "https://jsonplaceholder.typicode.com/users/1";
	HttpResponseMessage response = await _httpClient.DeleteAsync(url);
	response.EnsureSuccessStatusCode();

(5)发送带Header的请求:身份验证、自定义Header
csharp

	// 创建请求消息,设置Header
	var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/users/1");
	request.Headers.Add("Authorization", "Bearer your-token-here"); // 身份验证Header
	request.Headers.Add("X-Custom-Header", "custom-value"); // 自定义Header
	
	// 发送请求
	HttpResponseMessage response = await _httpClient.SendAsync(request);
  1. 进阶:用IHttpClientFactory管理HttpClient(推荐)
    IHttpClientFactory是.NET Core 2.1+引入的,专门用来管理HttpClient的生命周期——它会自动复用底层的HttpMessageHandler,避免端口耗尽,还能方便地配置超时、代理、Header等。
    步骤1:注册IHttpClientFactory
    在Program.cs中注册:
    csharp
	var builder = WebApplication.CreateBuilder(args);
	
	// 注册IHttpClientFactory
	builder.Services.AddHttpClient();
	
	var app = builder.Build();

步骤2:注入并使用
在控制器或服务中注入:
csharp

	public class UserService
	{
	private readonly IHttpClientFactory _httpClientFactory;
	
	// 构造函数注入IHttpClientFactory
	public UserService(IHttpClientFactory httpClientFactory)
	{
	_httpClientFactory = httpClientFactory;
	}
	
	public async Task<User> GetUserAsync(int id)
	{
	// 创建HttpClient
	var httpClient = _httpClientFactory.CreateClient();
	string url = $"https://jsonplaceholder.typicode.com/users/{id}";
	HttpResponseMessage response = await httpClient.GetAsync(url);
	response.EnsureSuccessStatusCode();
	return await response.Content.ReadFromJsonAsync<User>() ?? new User();
	}
	}

三、HttpListener:轻量级HTTP服务器的“神器”
HttpListener是.NET自带的轻量级HTTP服务器,不需要搭ASP.NET Core,几行代码就能写一个能处理HTTP请求的服务器——适合写工具类程序、测试服务器、轻量级API。
注意:HttpListener需要管理员权限才能运行(因为要绑定端口),或者用netsh命令注册URL:
bash
netsh http add urlacl url=http://+:8080/ user=DOMAINusername

  1. C#实战:用HttpListener写一个简单的HTTP服务器
    csharp
	using System;
	using System.Net;
	using System.Text;
	using System.Threading.Tasks;
	
	namespace HttpListenerDemo;
	
	class Program
	{
	static async Task Main(string[] args)
	{
	// 1. 创建HttpListener实例
	using var listener = new HttpListener();
	
	// 2. 添加要监听的URL前缀:http://+:8080/ 表示监听所有IP的8080端口
	listener.Prefixes.Add("http://localhost:8080/");
	listener.Prefixes.Add("http://127.0.0.1:8080/");
	
	try
	{
	// 3. 启动服务器
	listener.Start();
	Console.WriteLine("HTTP服务器已启动,监听端口8080...");
	
	while (true)
	{
	// 4. 异步等待客户端请求:GetContextAsync会阻塞当前线程,直到有请求进来
	HttpListenerContext context = await listener.GetContextAsync();
	// 5. 处理请求:用Task.Run避免阻塞主线程,同时处理多个请求
	_ = Task.Run(() => ProcessRequest(context));
	}
	}
	catch (Exception ex)
	{
	Console.WriteLine($"服务器异常:{ex.Message}");
	}
	finally
	{
	// 6. 停止服务器
	listener.Stop();
	}
	}
	
	// 处理单个HTTP请求
	private static async Task ProcessRequest(HttpListenerContext context)
	{
	// 1. 获取请求和响应对象
	HttpListenerRequest request = context.Request;
	HttpListenerResponse response = context.Response;
	
	try
	{
	Console.WriteLine($"收到请求:{request.HttpMethod} {request.Url}");
	
	// 2. 根据请求路径和方法处理业务逻辑
	string responseString = string.Empty;
	if (request.HttpMethod == "GET" && request.Url?.AbsolutePath == "/")
	{
	responseString = "欢迎访问HTTP服务器!";
	}
	else if (request.HttpMethod == "GET" && request.Url?.AbsolutePath.StartsWith("/users/") == true)
	{
	// 解析用户ID:比如/users/1,提取1
	string id = request.Url.AbsolutePath.Split('/')[2];
	responseString = $"用户ID:{id},姓名:张三";
	}
	else
	{
	// 404 Not Found
	response.StatusCode = (int)HttpStatusCode.NotFound;
	responseString = "404 页面不存在";
	}
	
	// 3. 把响应字符串转换成字节数组
	byte[] buffer = Encoding.UTF8.GetBytes(responseString);
	
	// 4. 设置响应头
	response.ContentLength64 = buffer.Length;
	response.ContentType = "text/plain; charset=utf-8";
	
	// 5. 把响应写入输出流
	await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
	}
	catch (Exception ex)
	{
	Console.WriteLine($"处理请求异常:{ex.Message}");
	response.StatusCode = (int)HttpStatusCode.InternalServerError;
	byte[] errorBuffer = Encoding.UTF8.GetBytes("500 服务器内部错误");
	response.ContentLength64 = errorBuffer.Length;
	await response.OutputStream.WriteAsync(errorBuffer, 0, errorBuffer.Length);
	}
	finally
	{
	// 6. 关闭响应输出流,释放资源
	response.OutputStream.Close();
	}
	}
	}

代码逐行讲:
1.new HttpListener();:创建HttpListener实例;
2.listener.Prefixes.Add("http://localhost:8080/");:添加要监听的URL前缀,必须以/结尾——比如http://localhost:8080/表示监听http://localhost:8080下的所有请求;
3.listener.Start();:启动服务器,开始监听请求;
4.HttpListenerContext context = await listener.GetContextAsync();:异步等待客户端请求,GetContextAsync会阻塞当前线程,直到有请求进来;
5._ = Task.Run(() => ProcessRequest(context));:用Task.Run把请求处理逻辑放到后台线程,避免阻塞主线程,这样服务器可以同时处理多个请求;
6.HttpListenerRequest request = context.Request;:获取请求对象,包含请求方法、URL、Header、请求体等;
7.HttpListenerResponse response = context.Response;:获取响应对象,用于设置状态码、Header、响应体等;
8.response.ContentLength64 = buffer.Length;:必须设置响应体的长度,否则客户端可能无法正确接收响应;
9.await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);:把响应体写入输出流;
10.response.OutputStream.Close();:关闭输出流,释放资源——必须关闭,否则客户端会一直等待响应。
2. 进阶:用HttpListener处理JSON请求和响应
csharp

	// 处理POST请求,接收JSON数据
	if (request.HttpMethod == "POST" && request.Url?.AbsolutePath == "/users")
	{
	// 读取请求体的JSON数据
	using var reader = new System.IO.StreamReader(request.InputStream, request.ContentEncoding);
	string jsonString = await reader.ReadToEndAsync();
	User newUser = JsonSerializer.Deserialize<User>(jsonString) ?? new User();
	
	// 模拟保存到数据库,生成ID
	newUser.Id = 100;
	
	// 返回JSON响应
	response.ContentType = "application/json; charset=utf-8";
	string responseJson = JsonSerializer.Serialize(newUser);
	byte[] buffer = Encoding.UTF8.GetBytes(responseJson);
	response.ContentLength64 = buffer.Length;
	await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
	}

四、HttpClient vs HttpListener:怎么选?
场景 选哪个? 原因
发送HTTP请求 HttpClient .NET官方封装,功能强大,用法简单
写轻量级HTTP服务器 HttpListener 不需要搭ASP.NET Core,几行代码就能跑
写企业级API服务器 ASP.NET Core 性能更高,支持路由、中间件、依赖注入等
五、基础知识拓展

  1. 怎么设置HttpClient的超时时间?
    默认超时时间是100秒,可以通过Timeout属性设置:
    csharp
    _httpClient.Timeout = TimeSpan.FromSeconds(30); // 设置超时时间为30秒
    如果需要无限超时(不推荐),可以设置为Timeout.InfiniteTimeSpan。
  2. 怎么处理HTTPS的自签名证书?
    如果服务器用的是自签名证书(比如测试环境),HttpClient会验证失败,需要跳过证书验证:
    csharp
	var handler = new HttpClientHandler();
	// 跳过证书验证(生产环境不要这么做!)
	handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
	using var httpClient = new HttpClient(handler);
  1. 怎么用HttpListener处理CORS?
    在响应头中添加Access-Control-Allow-Origin:
    csharp
	response.Headers.Add("Access-Control-Allow-Origin", "*"); // 允许所有域名访问
	response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
	response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization");

六、总结:C# HTTP编程的两个核心工具
HttpClient:发HTTP请求的首选,全局单例或用IHttpClientFactory,避免端口耗尽;
HttpListener:写轻量级HTTP服务器的神器,不需要搭ASP.NET Core,适合工具类程序、测试服务器;
进阶:企业级API服务器用ASP.NET Core,性能更高,生态更完善。

 本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49519.html


相关教程