一、基础 http 请求方法
1. httpclient 基础用法
// get 请求示例 async task<string> getdataasync(string url) { using var httpclient = new httpclient(); httpresponsemessage response = await httpclient.getasync(url); response.ensuresuccessstatuscode(); return await response.content.readasstringasync(); } // post 请求示例 async task postdataasync(string url, object data) { using var httpclient = new httpclient(); var json = jsonserializer.serialize(data); var content = new stringcontent(json, encoding.utf8, "application/json"); var response = await httpclient.postasync(url, content); response.ensuresuccessstatuscode(); }
警告:不要每次请求创建新 httpclient
!这会导致:
- 端口耗尽 (time_wait 状态)
- dns 更新延迟
- 连接池无法复用
二、高性能 http 客户端实践
1. ihttpclientfactory 最佳实践
// 1. startup 注册服务 services.addhttpclient("financeapi", client => { client.baseaddress = new uri("https://api.finance.com"); client.timeout = timespan.fromseconds(15); client.defaultrequestheaders.add("accept", "application/json"); }); // 2. 控制器中使用 public class datacontroller : controller { private readonly ihttpclientfactory _factory; public datacontroller(ihttpclientfactory factory) => _factory = factory; public async task<iactionresult> getstockdata() { var client = _factory.createclient("financeapi"); var response = await client.getasync("/stocks/msft"); // ... } }
2. http/2 连接复用
var handler = new socketshttphandler { pooledconnectionlifetime = timespan.fromminutes(5), enablemultiplehttp2connections = true }; var client = new httpclient(handler) { defaultrequestversion = httpversion.version20, defaultversionpolicy = httpversionpolicy.requestversionexact };
3. 流式处理大响应
// 避免大响应阻塞内存 async task processlargeresponse(string url) { using var client = new httpclient(); using var response = await client.getasync(url, httpcompletionoption.responseheadersread); using var stream = await response.content.readasstreamasync(); await using var buffer = new bufferedstream(stream); using var reader = new streamreader(buffer); while (!reader.endofstream) { var line = await reader.readlineasync(); processline(line); // 逐行处理 } }
三、高级场景实现
1. 自定义重试策略
// 指数退避重试器 async task<t> executewithretry<t>(func<task<t>> action, int maxretries = 3) { int retrycount = 0; while (true) { try { return await action(); } catch (httprequestexception ex) when (ex.statuscode == httpstatuscode.toomanyrequests) { if (retrycount++ >= maxretries) throw; var delay = timespan.fromseconds(math.pow(2, retrycount)); await task.delay(delay); } } } // 使用示例 var data = await executewithretry(() => getdataasync("https://unstable-api.com/data"));
2. 动态请求头签名
// 安全 api 调用签名 async task sendsignedrequest(string url) { var handler = new customsignaturehandler(); var client = new httpclient(handler); // ... 正常调用 } class customsignaturehandler : delegatinghandler { protected override async task<httpresponsemessage> sendasync( httprequestmessage request, cancellationtoken canceltoken) { // 1. 获取时间戳 var timestamp = datetimeoffset.utcnow.tounixtimemilliseconds(); // 2. 生成签名 var signdata = $"{request.method}{request.requesturi}{timestamp}{api_secret}"; var signature = hmacsha256.hash(signdata); // 3. 添加安全头 request.headers.add("x-timestamp", timestamp.tostring()); request.headers.add("x-signature", convert.tobase64string(signature)); return await base.sendasync(request, canceltoken); } }
四、性能优化策略
1. 连接管理优化
参数 | 推荐值 | 作用 |
---|---|---|
maxconnectionsperserver | 50-100 | 控制单个主机最大连接数 |
pooledconnectionidletimeout | 1-2 分钟 | 空闲连接保持时间 |
pooledconnectionlifetime | 5-10 分钟 | 连接最大存活时间 |
2. 响应处理优化技巧
// 高效 json 反序列化 async task<t> parsejsonresponse<t>(httpresponsemessage response) { // 使用流式 api 避免大对象分配 await using var stream = await response.content.readasstreamasync(); return await jsonserializer.deserializeasync<t>(stream, new jsonserializeroptions { propertynamecaseinsensitive = true, defaultbuffersize = 8192 // 8kb 缓冲区 }); } // 使用 arraypool 处理二进制响应 async task processbinaryresponse(string url) { var response = await _httpclient.getasync(url); var buffer = arraypool<byte>.shared.rent(1024 * 64); try { await using var stream = await response.content.readasstreamasync(); int bytesread; while ((bytesread = await stream.readasync(buffer)) > 0) { processchunk(new readonlyspan<byte>(buffer, 0, bytesread)); } } finally { arraypool<byte>.shared.return(buffer); } }
五、常见问题解决方案
1. dns 更新问题
// 强制刷新 dns 缓存 var handler = new socketshttphandler { pooledconnectionlifetime = timespan.fromminutes(5), // 设置连接生命周期 pooledconnectionidletimeout = timespan.fromseconds(30) };
2. 证书验证处理
// 开发环境忽略证书错误(生产环境禁用!) var handler = new httpclienthandler { servercertificatecustomvalidationcallback = (_, _, _, _) => true };
3. 多部分表单上传
async task uploadfile(string url, string filepath) { using var content = new multipartformdatacontent(); using var filestream = file.openread(filepath); content.add(new streamcontent(filestream), "file", "data.zip"); content.add(new stringcontent("2024-report"), "description"); var response = await _httpclient.postasync(url, content); response.ensuresuccessstatuscode(); }
六、性能监控与诊断
1. httpclient 指标监控
# 查看连接池状态 dotnet-counters monitor -n myapp system.net.http
2. 请求跟踪
// 添加日志记录器 services.addhttpclient("loggingclient") .configureprimaryhttpmessagehandler(() => new logginghandler(new socketshttphandler())); class logginghandler : delegatinghandler { protected override async task<httpresponsemessage> sendasync( httprequestmessage request, cancellationtoken cancellationtoken) { var stopwatch = stopwatch.startnew(); try { return await base.sendasync(request, cancellationtoken); } finally { _logger.loginformation($"{request.method} {request.requesturi} took {stopwatch.elapsedmilliseconds}ms"); } } }
最佳实践总结:
- 连接管理:始终重用
httpclient
,通过工厂管理生命周期 - 协议选择:启用 http/2 提升并发性能(尤其在高延迟网络)
- 资源控制:流式处理响应,避免大内存分配
- 弹性策略:实现重试/熔断机制(推荐使用 polly)
- 监控保障:持续跟踪请求延迟和错误率
性能对比:
场景 | 原始方式 | 优化方式 | 提升幅度 |
---|---|---|---|
1000次连续请求 | 28秒 | 9.2秒 | 3倍 |
10mb json 响应 | 1.2秒 | 0.4秒 | 3倍 |
高并发连接 | 350 qps | 1200 qps | 3.4倍 |
以上就是c#实现http请求的多种方案的详细内容,更多关于c#实现http请求的资料请关注代码网其它相关文章!
发表评论