I've got some problems concerning CORS/HttpClient in dotnet core. First of all my Application is structured like this:
Webapp -> Microservice-Gateway -> multiple Microservices
If I do an Ajax call from my Webapp
$.ajax({
url: "https://[actual gateway Url]/customer/" + customerId,
type: "GET",
timeout: 60000,
crossDomain: true,
dataType: "json",
success: data => {
//...
}
});
to the Gateway-Server I receive sometimes following error Message:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:50595' is therefore not allowed access. The response had HTTP status code 500.
Internally however my gateway throws this error if I debug:
System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.Http.WinHttpException: The operation timed out
I tried to solve the first error by adding following code in the gateway and every microservice:
public void ConfigureServices(IServiceCollection services) {
var corsBuilder = new CorsPolicyBuilder();
corsBuilder.AllowAnyHeader();
corsBuilder.AllowAnyMethod();
corsBuilder.AllowAnyOrigin();
corsBuilder.AllowCredentials();
services.AddCors(options => {
options.AddPolicy("SiteCorsPolicy", corsBuilder.Build());
});
//..
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
app.UseCors("SiteCorsPolicy");
//..
}
And just to be sure I also added
[EnableCors("SiteCorsPolicy")]
to every controller. The second problem I tried to solve by creating an HttpClient as Singleton in my Gateway and modifying following properties:
var client = new HttpClient();
client.Timeout = new TimeSpan(0, 10, 0);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
services.AddSingleton(client);
My gateway sends HTTP-requests like that:
[HttpGet("{id}")]
public async Task<JsonResult> GetById(int id) {
var response = await _client.GetAsync(new Uri(ServiceUrls.Customer + $"{id}"));
if (!response.IsSuccessStatusCode)
return new JsonResult(BadRequest($"{(int)response.StatusCode}: {response.ReasonPhrase}"));
var customer = JsonConvert.DeserializeObject<CustomerViewModel>(await response.Content.ReadAsStringAsync());
return new JsonResult(customer);
}
As I said, sometimes it works and sometimes it doesn't. Maybe you could give me some ideas whats my mistake. Thanks in advance!
Edit: The problem seems to appear more often if there are multiple async ajax calls from the Webapp at once. But this could also be just a feeling.
-
Can you share where you defined your 'SiteCorsPolicy' policy @Simon?Anthony Liriano– Anthony Liriano2018年05月09日 11:37:43 +00:00Commented May 9, 2018 at 11:37
-
"options.AddPolicy("SiteCorsPolicy", corsBuilder.Build());" in the fifth Code segmentSimon– Simon2018年05月09日 11:40:06 +00:00Commented May 9, 2018 at 11:40
-
The problem is 500 error, and that’s unrelated to your CORS configuration. It’s just that like most servers, this one only adds the Access-Control-Allow-Origin and other custom-configured response headers to 2xx success messages, not to 5xx and 4xx errors.sideshowbarker– sideshowbarker2018年05月09日 11:59:52 +00:00Commented May 9, 2018 at 11:59
-
Thanks @sideshowbarker! That narrows it down to the HttpClient. I've read multiple times that HttpClient is thread safe, is that wrong? I can't really think of another reason it should fail.Simon– Simon2018年05月09日 12:10:41 +00:00Commented May 9, 2018 at 12:10
-
stackoverflow.com/questions/11178220/… seems to be the canonical answer about HttpClient thread safety.sideshowbarker– sideshowbarker2018年05月09日 12:20:21 +00:00Commented May 9, 2018 at 12:20
3 Answers 3
This probably has nothing to do with your CORS setup. When an error occurs (the HTTP call using HttpClient for example), the default exception handler middleware removes all response headers and returns the error response. This means that any CORS header added by your policy will be removed, therefore you'll receive the error about "No 'Access-Control-Allow-Origin' header is present on the requested resource.".
To overcome this you should handle any exceptions in the controller yourself and return the appropriate error result, or write middleware before or replace the default exception middleware with your own exception handling logic.
There is also an open GitHub issue about this behavior: https://github.com/aspnet/Home/issues/2378.
1 Comment
Ok guys,
thanks for getting me into the right direction. I think I found a workaround/fix. I had to set following property in my gateway:
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
Comments
I came upon this issue too, .NET Core 2.0 does not return http status codes on non-200 or non-300 responses. I fixed it by creating middlewear to sit in the creationg of the Response to be sent back to the client.
You can take a look at all the steps here: https://medium.com/@arieldiaz92/net-core-2-0-fix-that-http-status-0-error-by-sending-cors-headers-on-failures-12fe3d245107