Unable to fetch POST without no-cors in header

On making request like that:

return fetch(
            'http://localhost:8000/login',
            {   method: 'POST',
                headers: new Headers(
                   {"Content-Type": "application/json",
                    "Accept":"application/json"}
                ),

                body: JSON.stringify(
                   {'name': 'Tom', 'password': 'Soyer'}
                )
             }
           ).then( response => { console.log(response);})
            .catch(err => console.log(err))

request running with method OPTIONS instead POST. Only on adding mode: 'no-cors' request become POST:

return fetch(
            'http://localhost:8000/login',
            {   method: 'POST',
                mode: 'no-cors',
                headers: new Headers(
                   {"Content-Type": "application/json",
                    "Accept":"application/json"}
                ),
                body: JSON.stringify(
                   {'name': 'Tom', 'password': 'Soyer'}
                )
             }
           ).then( response => { console.log(response);})
            .catch(err => console.log(err))

but response not ok than (even if network response status is 200): {type: "opaque", url: "", status: 0, ok: false, statusText: ""…} I suppose it because

The only allowed values for the Content-Type header are: application/x-www-form-urlencoded multipart/form-data text/plain

described here https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Is any way bring to live POST json data with fetch?


The custom Content-Type header you're sending causes your request to be preflighted, which means an OPTIONS request, containing some metadata about the POST request that is about to be dispatched, will be sent before the actual POST request.

Your server needs to be prepared to deal with this OPTIONS request. You haven't specified what the server is written in, but with express for example, you can register a middleware that intercepts all 'OPTIONS' requests, sets the Access-Control-Allow-Origin: * and Access-Control-Allow-Headers: Content-Type headers, and responds with 200.

If it is possible for you to make the request using a 'Content-Type': 'text/plain' header, that would solve your problem. Alternatively you could use something that bypasses XHR entirely, like JSONP.


When using non-cors, all headers must be valid simple-headers. The only valid values for the content-type header that qualifies as a simple-header is:

headers: [
  ['Content-Type', 'application/x-www-form-urlencoded'],
  ['Content-Type', 'multipart/form-data'],
  ['Content-Type', 'text/plain'],
]

Exceptions with contingencies:

headers: [
  ['Content-Type', 'application/csp-report'],
  ['Content-Type', 'application/expect-ct-report+json'],
  ['Content-Type', 'application/xss-auditor-report'],
  ['Content-Type', 'application/ocsp-request'],
]
  • simple-header
  • cors-protocol-exceptions