最稳妥的 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
Uri.EscapeDataString() 手动拼接,或借助 FormUrlEncodedContent + PostAsync 模拟(不推荐);更安全的是用 HttpClient.BaseAddress 和 string.Concat() 构建完整 URIContent-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 构造时已设的类型application/json; charset=utf-8,StringContent 默认已包含,无需额外处理StreamContent + FileStream 流式上传,避免内存峰值Bearer Token、API Key 等认证信息必须在发起请求前写入 client.DefaultRequestHeaders,而不是每次调用 PostAsync 时临时加——后者在并发场景下可能被覆盖或遗漏。
DefaultRequestHeaders.Authorization 里硬编码,改用 DelegatingHandler 拦截重试逻辑Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pass}")) 生成 credential,再设为 client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64)
User-Agent header,漏掉会返回 403;可统一加: client.DefaultRequestHeaders.UserAgent.ParseAdd("myapp/1.0")
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。
来电咨询