为什么HttpClient在请求成功后会抛出异常?

Why does HttpClient throw an exception when the request is successful?

我在 Web 请求的上下文中使用 HttpClient 发送另一个 Web 请求,如下所示:

private async Task SendManagerInfoAsync(Uri baseUri, string accessToken, object obj,
    string apiPath, HttpMethod httpMethod)
{
    string authToken = await GetManagerAuthToken(baseUri, accessToken)
        .ConfigureAwait(false);

    string url = new Uri(baseUri, apiPath).AbsoluteUri;

    var request = new HttpRequestMessage(httpMethod, url)
    {
        Content = new StringContent(JsonConvert.SerializeObject(obj))
    };
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    request.Headers.Add("Authorization", authToken);

    // For whatever reason, always throws a TaskCanceledException.
    var response = await m_httpClient.SendAsync(request).ConfigureAwait(false);

    response.EnsureSuccessStatusCode();
}

我正在追踪的请求是一个 HTTP PUT。出于某种原因,一旦达到预设的 HttpClient.Timeout 长度(大约 30 秒),此代码总是会抛出 TaskCanceledException。但是,当我检查此请求的接收者时,我发现数据存储 总是 已经更新了我在原始请求的一秒内 发送的信息.

我不明白为什么 HttpClient 实例在请求实际成功时会抛出异常。未请求取消令牌。有没有人见过这样的行为?


* 我将这个问题标记为与 Akamai 相关,因为只有当我们为接收请求的服务器打开 Akamai 服务的开关时,我才能观察到这种行为。

我最终检查了 HttpClient 发送的明显不成功的请求和 Chrome Postman 发送的成功请求。 HttpClient 默认情况下在每个请求中包含 Expect: 100-continue header。我按如下方式禁用它,请求又开始正常运行了。

m_httpClient.DefaultRequestHeaders.ExpectContinue = false;

(关于 为什么 这有效,我没有一个好的答案,但它让我暂时再次前进。)


Edit:它似乎以这种方式工作,因为 Akamai 严格解释 RFC 2616 8.2.3,它声明一个源服务器,如果它收到带有 [=13] 的请求=] header,

  • MUST either respond with 100 (Continue) status and continue to read from the input stream, or respond with a final status code

  • MUST NOT perform the requested method if it returns a final status code

所以 Akamai 仍在等待 100 响应代码,它永远不会得到,因此请求超时,这转化为 HttpClient 抛出的 TaskCanceledException

我仍然不知道为什么 HttpClient.DefaultRequestHeaders.ExpectContinue 默认 true 而不是 false,但这是另一天的问题。