最稳妥的 HttpClient 用法是复用而非每次新建,应声明为静态字段或 DI 单例;GET 请求需用 EnsureSuccessStatusCode() 处理错误状态码,POST JSON 必须设置 Content-Type,认证信息应通过 DefaultRequestHeaders 预设,错误处理需兼顾网络异常与 HTTP 状态码。

用 HttpClient 发起 GET 请求最稳妥
直接 new HttpClient 是常见错误起点——它本应复用,而非每次请求都新建。长期运行的服务若频繁创建销毁,会耗尽 socket 连接,触发 SocketException 或 HttpRequestException: Connection refused。推荐将 HttpClient 声明为静态字段或通过 DI 注册为单例。
基础 GET 示例:
var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/users");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
-
EnsureSuccessStatusCode()会抛出异常(如 404/500),避免手动检查response.IsSuccessStatusCode - 若需设置超时,用
client.Timeout = TimeSpan.FromSeconds(10);,别在GetAsync外套Task.Wait()或Task.Result - GET 参数建议用
Uri.EscapeDataString()手动拼接,或借助FormUrlEncodedContent+PostAsync模拟(不推荐);更安全的是用HttpClient.BaseAddress和string.Concat()构建完整 URI
POST JSON 数据必须设对 Content-Type
发 JSON 到 REST API 时,漏设 Content-Type: application/json 是 400 Bad Request 的头号原因。.NET 6+ 可用 JsonSerializer.SerializeToUtf8Bytes() 避免字符串编码开销;老版本建议用 StringContent 并显式指定编码。
示例(兼容 .NET 5+):
var client = new HttpClient();
var data = new { name = "Alice", email = "a@example.com" };
var json = JsonSerializer.Serialize(data);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.example.com/users", content);
- 不要用
content.Headers.ContentType = new MediaTypeHeaderValue(...)覆盖StringContent构造时已设的类型 - 若 API 要求
application/json; charset=utf-8,StringContent默认已包含,无需额外处理 - 大对象 POST 建议用
StreamContent+FileStream流式上传,避免内存峰值
带认证的请求要小心 header 注入时机
Bearer Token、API Key 等认证信息必须在发起请求前写入 client.DefaultRequestHeaders,而不是每次调用 PostAsync 时临时加——后者在并发场景下可能被覆盖或遗漏。
- Token 过期需刷新?别在
DefaultRequestHeaders.Authorization里硬编码,改用DelegatingHandler拦截重试逻辑 - Basic Auth 推荐用
Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pass}"))生成 credential,再设为client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64) - 某些 API(如 GitHub)要求
User-Agentheader,漏掉会返回 403;可统一加:client.DefaultRequestHeaders.UserAgent.ParseAdd("myapp/1.0")
错误处理不能只靠 try-catch
HttpRequestException 只覆盖网络层失败(DNS 错、连接断),但 HTTP 状态码如 401、422、503 会进到 response.IsSuccessStatusCode == false 分支。忽略这点,会导致业务逻辑把错误响应当成功数据解析。
- 统一检查
response.StatusCode:401 走登录刷新,422 解析response.Content提取errors字段,503 可考虑指数退避重试 - 反序列化前务必确认
response.Content.Headers.ContentType?.MediaType == "application/json",否则JsonSerializer.Deserialize可能抛() JsonException - 日志中记录
response.RequestMessage?.RequestUri和response.StatusCode,但切勿打response.Content.ReadAsStringAsync()的原始响应体(含敏感数据或超大 payload)
Content-Type;或要求 PUT 但实现只认 PATCH。这些没法靠通用封装解决,得留一两个裸 HttpClient.SendAsync() 调用点,方便快速验证 raw request/response。










