c# 如何调用 rest api

13次阅读

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

c# 如何调用 rest api

HttpClient 发起 GET 请求最稳妥

直接 new HttpClient 是常见错误起点——它本应复用,而非每次请求都新建。长期运行的服务若频繁创建销毁,会耗尽 socket 连接,触发 SocketExceptionHttpRequestException: 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.BaseAddressstring.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-8StringContent 默认已包含,无需额外处理
  • 对象 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-Agent header,漏掉会返回 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?.RequestUriresponse.StatusCode,但切勿打 response.Content.ReadAsStringAsync() 的原始响应体(含敏感数据或超大 payload)

实际集成时,最难缠的是第三方 API 文档写得模糊:比如声称“返回 JSON”,实际空 body 时没设 Content-Type;或要求 PUT 但实现只认 PATCH。这些没法靠通用封装解决,得留一两个裸 HttpClient.SendAsync() 调用点,方便快速验证 raw request/response。

text=ZqhQzanResources