使用HttpClient请求,问题记录

上篇博客说到使用单例HttpClient,以GET请求方法为例。可以看到对于Http请求头中Authorization参数,会根据传入的accessToken是否为空来判断是否添加此请求头。

        public async Task<HttpResponseMessage> GetRequestAsync(string requestUri, string accessToken)
{
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, requestUri);
if (!string.IsNullOrEmpty(accessToken))
{
message.Headers.Add("Authorization", "Bearer " + accessToken);
}
try
{
var response = await _httpClient.SendAsync(message);
//var response = await this._client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
return response;
}
else
{
throw new Exception(response.Content.ReadAsStringAsync().Result);
}
}
catch (Exception ex)
{
throw ex;
}
}

假设现在有两类请求,一类accessToken有值,一类accessToken值为null。那么在高并发请求中(两类请求都有),经常会曝出如下异常信息。

<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>AuthenticationFailed</code>
<message xml:lang="en-US">Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:6c793977-1002-0001-25dc-9ace78000000
Time:2018-12-23T16:24:40.3625699Z</message>
</error>

之前一直以为是并行代码有问题,因为使用串行代码执行是能正常运行的。后来测试的时候对并行请求那块代码加lock锁,同样会报这个错误。那么说明并行代码应该是没问题的。

因为报这个错误的请求都是accessToken为null的这类请求。而这类请求由于做了判断,请求头中并不应该有Authorization参数,而异常信息却说我的Authorization格式不正确,那么

似乎是accessToken为null的这类请求的请求头中有key为Authorization的请求头,只是value值不正确,但这类请求是不应该有key为Authorization的请求头的。

后来看到这篇文档(https://mitra.computa.asia/articles/msdn-azure-batch-server-failed-authenticate-request),发现是因为客户端的代理层(proxy layer)会缓存请求信息。也就是说在高并发请求中,带Authorization请求头的请求会缓存下来(而我猜测这因为有一个很短的过期时间,不然就无法解释串行请求是正常的),当切换到不应该带Authorization请求头的请求时(因为Authorization请求头的值为空),就会出现此异常。所以我们需要将Proxy禁用掉就可以的。

//创建HttpClient对象时,禁用Proxy
HttpClientHandler handler = new HttpClientHandler()
{
UseProxy = false
};
_httpClient = new HttpClient(handler);

或者也可以使用如下方式禁用客户端Proxy

  <system.net>
<requestCaching defaultPolicyLevel="NoCacheNoStore"/>
</system.net>

这样客户端Proxy就不会缓存Http信息了,两类请求在高并发场景下也能互不干扰。

上一篇:第五节:什么导致Finalize方法被调用


下一篇:工作中常用的Linux命令:crontab命令