1

I open a static page from the file system which tries to fetch a resource from a server running on localhost ( namely a directory listing of / ). The browser refuses to forward this request and suggests:

If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Then I submit the request using 'no-cors':

let body=JSON.stringify({action:"listfiles",path:"/"})

let headers = new Headers()
headers.append("Content-Type", "application/json");               

fetch('http://localhost:9000/ajax',{
    method: 'POST',
    headers: headers,
    body: body,
    mode: 'no-cors'
}).then(
    response=>response.json()
).then(
    data=>this.onload(data)
)

On the server side I use express in the following way:

app.use('/ajax',bodyParser.json())

app.post("/ajax",function(req,res){    
  let action=req.body.action  
  console.log(`ajax ${action}`)
}

This time the browser lets the request through, and even app.post gets the request, just the request body is not parsed correctly, instead of 'listfiles' I get undefined value for action. ( The same problem does not occur if I load the page from localhost ).

sbtpr
  • 541
  • 5
  • 18
  • See https://stackoverflow.com/questions/42254685/text-response-is-empty-when-using-fetch/42255007#42255007 and https://stackoverflow.com/questions/43317967/handle-response-syntaxerror-unexpected-end-of-input/43319482#43319482. You basically never want to use "mode: 'no-cors'". It tells browsers to completely block your frontend JavaScript from accessing the response body and headers. – sideshowbarker Nov 22 '17 at 20:42

2 Answers2

1

Because you're trying to make a cross-origin call (the protocol file: is not the same as the protocol http:). The Same Origin Protocol is enforced by the browser, so it's not surprising your server sees the request. The request doesn't contain CORS headers that would allow the browser to give the response to your code, so it doesn't; and you've disabled CORS anyway.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I think my problem is that my request triggers a preflight. My request contains an 'application/json' Content-Type header, so that body-parser would parse the json from it. Only simple GET, HEAD, POST requests don't trigger a preflight if they contain only the allowed headers and in particular the Content-Type header's ( which itself is an allowed header ) allowed values are application/x-www-form-urlencoded, multipart/form-data and text/plain for the request to qualify as simple. – sbtpr Nov 22 '17 at 16:55
  • 1
    @sbtpr: No, even if it didn't trigger a preflight, you'd still be expected to set the relevant headers on the actual POST response. (If there's a preflight, they have to be on **both** responses. If not, just the GET/POST/HEAD response.) – T.J. Crowder Nov 22 '17 at 17:12
0

From https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS :

" The Cross-Origin Resource Sharing standard works by adding new HTTP headers that allow servers to describe the set of origins that are permitted to read that information using a web browser. Additionally, for HTTP request methods that can cause side-effects on server's data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. "

The problem with my request is that it does not qualify as simple. This is because it contains a Content-Type: application/json header, in order that the body-parser middle-ware would parse the document body as json. Therefore it triggers a preflight request.

" Simple requests

Some requests don’t trigger a CORS preflight. Those are called “simple requests” in this article, though the Fetch spec (which defines CORS) doesn’t use that term. A request that doesn’t trigger a CORS preflight—a so-called “simple request”—is one that meets all the following conditions: ... "

Conditions listed here include restrictions on methods, the headers you can set etc. Please look at the doc for details.

While the method I use ( POST ) is allowed in a simple request, and also setting the Content-Type header is allowed for a simple request, the only possible values for Content-Type are

application/x-www-form-urlencoded
multipart/form-data
text/plain

for a request to qualify as simple.

Since my server does not know about preflight requests, it is natural that it could not handle my request properly.

Also see the comment to the answer, as to which additional headers need to be passed on the client and the server side for the request to work as expected.

Community
  • 1
  • 1
sbtpr
  • 541
  • 5
  • 18
  • 1
    See note [here](https://stackoverflow.com/questions/47436830/why-does-body-parser-fail-when-i-fetch-the-resource-in-no-cors-mode/47436936?noredirect=1#comment81835710_47436936); the fact the request isn't simple is not the only reason it doesn't work without CORS. – T.J. Crowder Nov 22 '17 at 17:22
  • Ok, I see now. Once I actually can forward the request to the server, I still need extra headers. I believe that in the request this is Origin ( Referer? ), and in the response Access-Control-Allow-Origin. – sbtpr Nov 22 '17 at 17:27
  • Yes. (Origin, not Referer.) You'll also probably need at least `Access-Control-Allow-Headers`. – T.J. Crowder Nov 22 '17 at 17:30