You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# HttpClient JSON请求体未正确应用及替代方案咨询

API请求体异常问题排查与解决方案

问题根源

你的代码里POST/PUT请求体无效的核心原因有三个:

  1. 重复序列化JSON:reqbody参数本身就是字符串类型的请求体,你却再次调用JsonConvert.SerializeObject(reqbody),这会把原本的JSON字符串转义成带双引号的嵌套字符串(比如{"name":"test"}变成"{\"name\":\"test\"}"),导致接口识别为无效格式。
  2. 缺少Content-Type头:Postman会自动为JSON请求添加Content-Type: application/json头,但你的StringContent没有设置这个属性,接口无法正确解析请求体格式。
  3. 异常错误标记401:WebException不一定是授权问题(比如本次是请求体错误),直接返回401会误导问题排查。

修正后的代码

private Tuple<int, string> API_Check(string URL, string reqtype, string reqbody, string split_username, string split_pwd)
{
    string responsetxt = "";
    HttpResponseMessage httpresult = new HttpResponseMessage();
    int statuscode = 0;
    ServicePointManager.Expect100Continue = true;
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | (SecurityProtocolType)3072; // 合并TLS版本,避免覆盖
    using (HttpClient _httpClient = new HttpClient()) // 用using包裹HttpClient,避免资源泄漏
    {
        var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{split_username}:{split_pwd}"));
        _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);

        try
        {
            if (reqtype == "GET")
            {
                httpresult = _httpClient.GetAsync(URL).Result;
            }
            else
            {
                // 直接使用reqbody字符串,不再重复序列化,同时设置Content-Type
                using (var content = new StringContent(reqbody, Encoding.UTF8, "application/json"))
                {
                    switch (reqtype)
                    {
                        case "PUT":
                            httpresult = _httpClient.PutAsync(URL, content).Result;
                            break;
                        case "POST":
                            httpresult = _httpClient.PostAsync(URL, content).Result;
                            break;
                    }
                }
            }

            statuscode = (int)httpresult.StatusCode;
            responsetxt = httpresult.Content.ReadAsStringAsync().Result;
            return Tuple.Create(statuscode, responsetxt);
        }
        catch (System.Net.WebException Excptn)
        {
            // 从响应中获取真实状态码,而不是硬编码401
            if (Excptn.Response is HttpWebResponse webResponse)
            {
                statuscode = (int)webResponse.StatusCode;
            }
            else
            {
                statuscode = 500;
            }
            
            using (var stream = Excptn.Response.GetResponseStream())
            using (var reader = new StreamReader(stream))
            {
                responsetxt = reader.ReadToEnd();
                MessageBox.Show(responsetxt);
            }
        }
        catch (Exception ex)
        {
            statuscode = 500;
            responsetxt = ex.Message;
            MessageBox.Show(responsetxt);
        }
    }
    return Tuple.Create(statuscode, responsetxt);
}

关于「不用HttpContent直接发字符串」的问题

HttpClient的PostAsync/PutAsync方法设计上必须接收HttpContent类型的参数,无法直接传入字符串。不过你可以通过StringContent直接包装原始字符串(就像上面修正后的代码那样),这本质就是把字符串作为请求体发送,和你想要的「直接发字符串」效果一致,不需要额外的转换步骤。

另外补充几个优化点:

  • 用using包裹HttpClient,避免资源泄漏;
  • 合并TLS版本设置,避免后面的赋值覆盖前面的;
  • 用switch替代多个if,代码更清晰;
  • 异常处理中获取真实的响应状态码,不再硬编码401。

内容的提问来源于stack exchange,提问作者ItsMeGokul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:00:17