4

Trying to make a cross-origing fetch request with the no-cors mode I found out it is not possible in this case to send any data to the server as a body:

const url = 'http://cross-origin-example.com/post';
const request = new Request(url, {
  method: 'POST',
  mode: 'no-cors',
  headers: {
    'Content-Type': 'text/plain',
  },
  body: 'boo',
});
fetch(url, request).then((response) => console.log(response));

In Chrome, such a request will not be sent at all throwing the following error:

Uncaught (in promise) TypeError: Failed to execute 'fetch' on 'Window': If request is made from ReadableStream, mode should be"same-origin" or "cors"

Firefox make the request reach the server but with the body missing.

I know when using the no-cors mode the JS code gets an opaque response, which effectively conceals the result of fetching. However, on what basis the browsers do not allow attach body in this case? Is it standardized behavior (in fact, I failed to find such a restriction somewhere in the fetch spec) or just a browser extra limitation?

1 Answer 1

0

Regarding Chrome's error:

This is because you pass a Request object as the init param of your fetch(input, init) call.
Doing so, the body of the new internal request will be set to the value of the body property exposed on the Request object, which is now a ReadableStream in browsers that do support Request#body (all but Firefox as of today). It will use the internal body of the Request only when there is no such property exposed. And when the new request is built, if its mode is neither "cors" nor "same-origin", it should throw.

console.log(new Request("./", {
  method: 'POST',
  body: 'boo',
}).body); // undefined in Firefox, a ReadableStream in Chrome and Safari

What you probably meant to do was fetch(request) instead, which would not create a new internal Request object, and will not throw.

Regarding the absence of body:

For no-cors requests browsers are indeed allowed to override the request, which is ultimately implementation-defined. So they're basically free to do whatever they want.
But, upon testing, it seems that as long as the preflight request is accepted, browsers will then happily send the body along with the request. So maybe, the server you were trying to hit did block the preflight request, or maybe it will handle the header 'sec-fetch-mode': 'no-cors' by ignoring the request's body, but the data should be sent by the browser nevertheless.

fetch('https://commons.wikimedia.org/', {
  method: 'POST',
  mode: 'no-cors',
  body: 'boo'
});
Check your own Network panel to see what's been sent. On my Chrome this gives:<br>

<img src=https://i.sstatic.net/DdJZd3O4.png alt="screenshot of a dev-tools network panel showing that the Request Payload for a request to commons.wikimedia.org was 'boo'" style="width:100%">

Sign up to request clarification or add additional context in comments.

6 Comments

Indeed, body: 'boo' in my question should be replaced by a new body with a ReadableStream object according to the spec you've cited.
However, as to that condition that causes throwing the error: If inputOrInitBody is non-null and inputOrInitBody’s source is null. Isn't inputOrInitBody’s source not null here? Seemingly, it should get a non-null value in the to extract a body with type routine.
No, source isn't set in the ReadableStream case, so it's returned as null
I've expressed myself not clearly. I meant if the body: 'boo' construction used (as in my question) the browser will replace the string with a ReadableStream as a body. It happens in the to extract a body with type routine, which gets in this case the boo string as a param. Encoding of the latter becomes the ReadableStream's source.
It can be verified that in my case the exception thrown in the fetch step, not in the new Request(...) one.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.