【问题标题】:C# .NET HttpClient POST returns an empty response sometimesC# .NET HttpClient POST 有时会返回空响​​应
【发布时间】:2022-04-29 01:07:03
【问题描述】:

我正在使用 HttpClient 向外部 API 发送 POST 请求,并且我知道我正在发送正确的有效负载和标头以及所有内容,因为它有时可以工作,但有时它会返回一个空字符串响应。它总是返回 200 状态码。将其更改为异步不是一种选择,所以我的问题是,我如何同步运行并可靠地获得响应?

这是我在我的应用程序的许多其他地方用于 GET 和 POST 的方法,并且每次都可以正常工作:

HttpClient client = new HttpClient { BaseAddress = new Uri("url")
client.DefaultRequestHeaders.Add("X-Authorization", "Bearer " + authToken);

var input = new {json object};

var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

var json = JsonConvert.SerializeObject(input, serializerSettings);
var data = new StringContent(json, Encoding.UTF8, "application/json");

var result = client.PostAsync("api/Create", data).Result;
if (result.IsSuccessStatusCode)
{
    var jsonStringResult = result.Content.ReadAsStringAsync().Result;
    var response = JsonConvert.DeserializeObject<ApiResponse>(jsonStringResult);
    // response is null....sometimes
}

我从其他论坛帖子和博客中尝试过的其他方法:

var postTask = client.PostAsync("api/Create", data);
postTask.Wait();
var result = postTask.Result;
if (result.IsSuccessStatusCode)
{
    var jsonTask = result.Content.ReadAsStringAsync();
    jsonTask.Wait();
    var jsonStringResult = jsonTask.Result;
    var response = JsonConvert.DeserializeObject<ApiResponse>(jsonStringResult);
    // response is null....sometimes
}

var result = client.PostAsync("api/Create", data).GetAwaiter().GetResult();
if (result.IsSuccessStatusCode)
{
    var jsonStringResult = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
    var response = JsonConvert.DeserializeObject<ApiResponse>(jsonStringResult);
    // response is null....sometimes
}

byte[] byteArray = Encoding.UTF8.GetBytes(json);

var request = (HttpWebRequest)WebRequest.Create("url");
request.Method = "POST";
request.ContentType = "application/json; charset=UTF-8";
request.Accept = "application/json";
request.ContentLength = byteArray.Length;
request.Headers.Add("X-Authorization", "Bearer" + authToken);

Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

WebResponse response = request.GetResponse();

dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();

dataStream.Close();
response.Close();

var responseObj = JsonConvert.DeserializeObject<ApiResponse>(responseFromServer);
// resonseObj is null...sometimes

所有四种方法在某些时候都有效,但我需要它更可靠。死锁目前不是问题。 任何帮助表示赞赏!

【问题讨论】:

  • 我建议您使用 Fiddler(或其他一些网络跟踪工具)来确认正文是从服务器返回的。您的客户可能没有任何问题。
  • 为什么不能选择异步?
  • 它是一个 Windows 窗体应用程序,可与微控制器通信并按特定顺序执行一系列操作。为了让一切正常工作需要付出很多努力。我尝试异步运行这部分,它把其他所有东西都扔了,但仍然没有比上面的其他方法更好。
  • 我遇到了一个非常相似的问题。就我而言,代码运行可靠,并且当它在各种 Windows 10 机器上运行时我得到了正确的响应,但在 Windows Server 上运行时大部分时间都失败了。你有解决它的进展吗?
  • @Avi 在 Windows 服务器上运行成功了吗?经过多少次尝试失败?

标签: .net httpclient


【解决方案1】:

在上面的评论中,我注意到我偶尔会遇到同样的空响应问题,但我终于弄清楚发生了什么并让我的代码正常工作。我必须解决两个问题:

  1. 我的用户代理标头。我使用的用户代理包含一堆不同的元素,比如Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36,当我将其更改为Mozilla/5.0 (Windows NT 10.0; Win64; x64) 时,一切都开始更加一致地工作。 (我在 Windows Server 环境中的响应为空,因此您可能需要调整它以使用户代理字符串与您自己的环境完全匹配。)

  2. 我曾使用 Postman 测试我的调用并获取它生成的生成代码,但在使用 Fiddler 时,我发现 Postman 发送的标头未在其生成的代码中输出。具体来说:Accept-Encoding: gzip, deflate, br。所以很自然,它没有包含在我的代码中。

当我修改我的 http 请求代码的这两个方面时,它始终如一地工作,没有任何空响应。但是,请注意,在添加 accept-encoding 标头后还必须调整一件事。响应被压缩,所以我必须指定 HttpClient 自动解压响应。我最终的 HttpRequest 初始化代码如下所示:

    Dim HttpClient = New HttpClient(New HttpClientHandler With {.UseCookies = False, .AutomaticDecompression = DecompressionMethods.GZip Or DecompressionMethods.Deflate})
    Try
        HttpClient.DefaultRequestHeaders.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
        HttpClient.Timeout = TimeSpan.FromSeconds(10)
        HttpClient.DefaultRequestHeaders.Add("authority", "https://blahblah")
        HttpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br")  
        HttpClient.DefaultRequestHeaders.Add("accept", "application/json, text/plain, */*")
        HttpClient.DefaultRequestHeaders.Add("accept-language", "en-US,en;q=0.9")
        HttpClient.DefaultRequestHeaders.Add("cookie", CookieVar)
        HttpClient.DefaultRequestHeaders.Add("origin", "https://blahblah")
        HttpClient.DefaultRequestHeaders.Add("referer", "https://blahblah")
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try

最后一点:一旦我使用 Fiddler 指定了 AutomaticDecompression 属性,我发现 Accept-Encoding 标头已自动添加到调用中,因此可以取出指定它的实际行。我把它留在上面只是为了说明我在说什么。

另外,要解释 HttpClientHandler 中的 .UseCookies = False 行,请参阅 here

【讨论】:

    猜你喜欢
    • 2018-05-13
    • 2021-09-09
    • 2019-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    相关资源
    最近更新 更多