my environments:
- backend (localhost) written in .net web api 2
enabled package "Microsoft.AspNet.WebApi.Cors" - frontend (localhost) with vue-js-2 with webpack-simple
vue-resource for http requests
I am experiencing some CORS issues which I cannot solve:
Launching "simple requests" with GET verb works, but when using POST verb I get CORS error, saying:
Access to XMLHttpRequest at 'http://localhost:59837/api/Employees' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I've read mozilla's CORS reference and noticed that indeed my POST request is sent as a preflight request first, with OPTIONS verb and Access-Control-Request-Method: POST
header.
on my WebApiConfig file I have:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...
// Web API enable CORS
System.Web.Http.Cors.EnableCorsAttribute cors = new System.Web.Http.Cors.EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
}
}
and my POST request code is as follows:
testPOST(){
const credentials = { username: '1', password: '11'};
this.$http.post('http://localhost:59837/api/Employees', {params: {id: '2'}, body: credentials, method: 'POST', headers: {'Content-Type': 'text/plain'}})
.then(function (response){
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
and the POST function in the controller:
public async Task<HttpResponseMessage> PostEmployees(Credentials creds)
{
Employees emp = await db.Employees.FindAsync(Int32.Parse(creds.username));
if (emp.password.Equals(creds.password))
{
emp.password = "";
return Request.CreateResponse(HttpStatusCode.OK, emp);
}
else
return Request.CreateResponse(HttpStatusCode.Unauthorized, "Username or password are incorrect");
}
My thinking was that perhaps I need to define the POST request headers to the authorized "text/plain". Using Fiddler I found the outgoing request but it didn't have the text/plain header.. Right now, I am not even sure if my error is related to the backend configuration or to the frontend request sending method. Any one encountered anything similar? (sorry for all the code, I wanted to be as encompassing yet minimal as possible)
Web Api 2 doesn't respond to OPTIONS request. You can add Handler for it. Here it is how i solved it once. Create a IHttpModule somewhere. Here is mine:
And add it in Web.config:
If it still dosen't respond to OPTIONS request for some method in your controller i see that i have added AcceptVerbs Attribute like that:
Solution
I think the problem was actually both front- and back-end related.
Microsoft's Web API 2's tutorial doesn't seem to mention its lack of support for the OPTIONS header that is generated by some clients as "pre-flight" request. In addition, the parameters I was using in Vue-Resource's also caused some problems.
Back-end:
1. I changed the default behavior that caused the server to drop all requests with OPTIONS header in Global.asax.cs, thanks Obelixx:
I'm really not sure that's the best solution, I'm sure there's a perfectly good reason why .net programmers thought all OPTIONS requests should be dropped, this needs deeper digging into it, so use with caution.
2. as can be seen here, I also added an OPTIONS actions in my controller class:
front-end:
1. vue-resource's API says has this signature for POST request:
but also sats you can include the body inside the config paramter.
well, didn't work for met. so instead of this:
I did this:
notice how i took the body: credentials out and just used credentials as a separate argument.
2. I also changed the 'Content-Type' header from text/plain to application/json (microsoft says that text/plain types should prevent the pre-flight, but that only caused my json formatter to fail parsing credentials).
----
So that's the solution for now, like I said I had both front- and back-end related fixes, I'm not sure if there were really so many bugs or just an undiscovered one that I patched in many places.
I hope this helps other people.