Search code examples
javascriptwcfiiscorsfetch

CORS error when using fetch with Content-Type


i'm trying to send a POST request to a REST web service from a different domain in FireFox. i'm using the JavaScript "fetch" function for this. i'm hosting the REST web service in IIS. it works fine before i add a "Content-Type" header in JavaScript.

CORS errors in the FireFox console

note that if i enable XHR in the console, then i can see that using fetch with the "Content-Type" results in an OPTIONS request. but, not using the "Content-Type" results in a POST request. so fetch is triggering a preflight request as the documentation says. these are the errors:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://example.com/Service.svc/Request. (Reason: CORS preflight response did not succeed).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://example.com/Service.svc/Request. (Reason: CORS request did not succeed).
TypeError: NetworkError when attempting to fetch resource.

JavaScript with CORS error

var body = '{ID:2, Name:"test reqx"}';
var url = "http://example.com/Service.svc/Request";
var init = {credentials:"include", method:"POST", headers:{"Content-Type":"application/json","Accept":"application/json"}, body:body};
fetch(url,init)
    .then(response => response.text())
    .then(data => console.log(data));

JavaScript without CORS error, but also no Content-Type

var body = '{ID:2, Name:"test reqx"}';
var url = "http://example.com/Service.svc/Request";
var init = {credentials:"include", method:"POST", headers:{"Accept":"application/json"}, body:body};
fetch(url,init)
    .then(response => response.text())
    .then(data => console.log(data));

i'm using 'credentials:"include"' because the REST web service is configured with Basic Authentication.

REST web service web.config (note the different domain)

i've added some CORS configurations, to make other requests work cross domain in FireFox. but, i can't find the right configuration to allow Content-Type:

<configuration>
    ...
    <system.webServer>
      <httpProtocol>
        <customHeaders>
          <add name="Access-Control-Allow-Origin" value="http://example.net" />
          <add name="Access-Control-Allow-Methods" value="OPTIONS,POST"/>
          <add name="Access-Control-Allow-Credentials" value="true" />
          <add name="Access-Control-Allow-Headers" value="Content-Type"/>
        </customHeaders>
      </httpProtocol>
      ...
    </system.webServer>
    ...
</configuration>

the REST web service does not work without the "Content-Type" header "application/json". how can i resolve these errors?

Side note

using HTTP instead of HTTPS, makes the examples easier (because no certificates needed), but it also sends the credentials for Basic Authentication in plain text


Solution

  • the selected answer, in the question referred to by Daniel A. White, was the solution although slightly modified. How to add cross domain support to WCF service.

    Side note

    i noticed different responses to the OPTIONS call when it's not yet fixed:

    • 405 Method Not Allowed: with Anonymous Authentication in IIS
    • 401 Unauthorized: with Basic Authentication in IIS but the CORS errors are the same in both cases as Daniel pointed out

    this is how i modified the WCF REST Web Service and got rid of the CORS errors:

    Global.asax.cs

    i also added the Global.asax.cs file to the web service. but i did not add any "Access-Control-Allow-Headers" in there, as it seems to overrule the web.config. so decided to shave it down to the bare minimum:

        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            // prevent 401 unauthorized response to CORS preflight check
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.End();
            }
        }
    

    Web.config

    i shaved this down to the bare minimum as well (make sure you have runAllManagedModulesForAllRequests="true")

    <configuration>
      ...
      <system.webServer>
        <modules runAllManagedModulesForAllRequests="true"/>
        ...
        <httpProtocol>
          <customHeaders>
            <add name="Access-Control-Allow-Origin" value="http://example.net" />
            <add name="Access-Control-Allow-Credentials" value="true" />
            <add name="Access-Control-Allow-Headers" value="Content-Type"/>
          </customHeaders>
        </httpProtocol>
        ...
      </system.webServer>
      ...
    </configuration>