我正在使用HttpClient来调用Web Api REST端点,偶尔我会看到一个随机的401 Unauthorized Status。
这是我的HttpClient包装器,它是为了可重用性而创建的。我修改了它以便在不修改核心部分的情况下保持这篇文章的简单。
public class HttpHelper
{
public const string JsonContentType = "application/json";
public T PostAsJsonObject<T>(string uri, T t) where T : class
{
using (HttpResponseMessage response = PostJsonHttpRequest(uri, JsonContentType, t))
{
response.EnsureSuccessStatusCode();
return response.Content.ReadAsAsync<T>().Result;
}
}
private HttpResponseMessage PostJsonHttpRequest<T>(string uri, string contentType, T content) where T : class
{
if (String.IsNullOrEmpty(uri))
{
throw new ArgumentNullException("uri");
}
HttpResponseMessage response = CreateHttpClient(contentType).PostAsJsonAsync(uri, content).Result;
return response;
}
private HttpClient CreateHttpClient(string contentType)
{
var credentials = new NetworkCredential("srvuser", "somepwd", "somedomain");
return new HttpClient(new HttpClientHandler { Credentials = credentials, PreAuthenticate = true });
}
}
以下是我如何调用它。
var httpHelper = new HttpHelper();
var response = httpHelper.PostAsJsonObject("https://xyz.pvt/inventory/api/orders", "234");
大部分时间它工作正常,但有一段时间我得到401 Unauthorized错误。我试图找出可能导致它的原因。
System.Net.Http.HttpRequestException:响应状态代码没有 表示成功:401(未经授权)。在 System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()at HttpHelper.PostAsJsonObject [T](String uri,T t)
我查看了asp.net日志,发现了一个奇怪的模式。大多数时候,我看到一对条目(401后跟200 OK),如
2017-02-09 12:04:13 104.68.45.152 POST /inventory/api/orders/ - 80 - 132.64.78.120 HTTP/1.1 - 401 2 5 764
2017-02-09 12:04:16 104.68.45.152 POST /inventory/api/orders/ - 80 somedomain\srvusr 132.64.78.120 HTTP/1.1 - 200 0 0 2917
2017-02-09 12:04:16 104.68.45.152 POST /inventory/api/orders/ - 80 - 132.64.78.120 HTTP/1.1 - 401 2 5 0
2017-02-09 12:04:19 104.68.45.152 POST /inventory/api/orders/ - 80 somedomain\srvusr 132.64.78.120 HTTP/1.1 - 200 0 0 2230
但偶尔我会看到401
2017-02-09 12:14:04 104.68.45.152 POST /inventory/api/orders/ - 80 - 132.64.78.120 HTTP/1.1 - 401 2 5 0
REST api是使用在.NET 4.6.1上运行的ASP.NET Web Api 2实现的,在IIS 7.5中,它只使用Windows身份验证进行设置。
不确定导致身份验证偶尔失败的原因。
更新
这是我使用async await pattern编写的新代码。
public class HttpHelper
{
public const string JsonContentType = "application/json";
private HttpClient CreateHttpClient(string url, string contentType)
{
var handler = new HttpClientHandler
{
Credentials = new CredentialCache { { new Uri(url), "NTLM", new NetworkCredential("srvuser", "somepwd", "somedomain") } },
PreAuthenticate = true
};
var httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
return httpClient;
}
private async Task<HttpResponseMessage> PostJsonHttpRequestAsync<T>(string url, string contentType, T content) where T : class
{
if (string.IsNullOrEmpty(url))
{
var exception = new ArgumentNullException("url");
throw exception;
}
var response = await CreateHttpClient(url, contentType).PostAsJsonAsync(url, content);
return response;
}
public async Task<T> PostAsJsonObjectAsync<T>(string uri, T t) where T : class
{
using (var response = await PostJsonHttpRequestAsync(uri, JsonContentType, t))
{
return await response.Content.ReadAsAsync<T>(new[]
{
new JsonMediaTypeFormatter
{
SerializerSettings = { NullValueHandling = NullValueHandling.Ignore, TypeNameHandling = TypeNameHandling.Auto }
}
}.AsEnumerable());
}
}
}
以下是我最终如何调用它。
static class TestMe
{
static void Main()
{
var httpHelper = new HttpHelper();
var responseTask = httpHelper.PostAsJsonObjectAsync("https://xyz.pvt/inventory/api/orders", "234");
responseTask.Wait(120000);
var response = responseTask.Result;
Console.WriteLine(response);
}
}
即使是现在我也看到同样的问题。仍然随机获得401 Unauthorized错误。
更新2
我做了一些调查,发现这些神秘的401错误来自IIS。当这些神秘的401错误发生时,IIS日志有一个相应的401错误条目,但在这种情况下,请求永远不会到达asp.net管道。好像由于某种原因IIS发回请求401错误。
我没有深入研究,我知道IIS中的Windows身份验证使用2个请求来根据HttpClient的配置来管理身份验证。因此,成功的身份验证请求将具有401.2,然后是200 OK。这是大部分时间发生的事情。偶尔你会注意到有一个401.2,然后只有401.重试尝试时的相同请求通过罚款(401.2后跟200 OK)。
真的很感激,如果有人对这个问题有一些了解,并且可以解决这个问题。
答案 0 :(得分:-2)
您确定您的代码甚至是问题吗?我不知道您的情况的详细信息,但Web服务器有时可能会无缘无故地向您发送401回复。
您可以采取以下措施来测试此理论:同时运行程序的两个(或更多)实例,最好是在不同的计算机上运行。等到你得到401错误。如果您的代码的所有实例同时开始收到401错误,那么它几乎肯定是Web服务器上的问题。