0

I am attempting to perform a simple fetch to a server I do not control:

fetch('https://path.to.the.server/api/items');

This is a GET endpoint. Using Firefox 52.9.0, if I paste my fetch code into the console and hit Enter, I see the GET request fail in the Network tab with a 401. And in the console, I receive the following errors:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://path.to.the.server/api/items. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

TypeError: NetworkError when attempting to fetch resource.

There's nothing here in this fetch that should be triggering CORS. Importantly, I do not see a preflight OPTIONS request in the Network tab prior to the 401. The 401 failure is on the GET request itself. However, the errors in the console still point to the browser being denied due to CORS.

So I'm confused why CORS is an issue here. This should be a simple fetch. Is there something I'm missing?

Note: This project is in an "offline" environment, which is why I have not linked the actual URL for community testing.

Matt
  • 23,363
  • 39
  • 111
  • 152
  • 1
    _"There's nothing here in this fetch that should be triggering CORS"_ Any request to another origin which does not allow CORS will throw a CORS error. It does not matter whether it's a GET, or a POST or a DELETE. If the origin is not allowed, the browser will block the response from reaching your script – blex May 26 '21 at 20:06
  • 1
    A GET request doesn't send a preflight request. It just rejects it when the response doesn't have the right headers. – Ivar May 26 '21 at 20:07
  • I should clarify: I meant there's nothing in this request that should trigger *a preflight OPTIONS request*, such that my browser would determine it cannot make the actual request. – Matt May 26 '21 at 20:10
  • I think @Ivar is right in that GET requests are not supposed to be altering anything on the server, so the browser just makes the request and checks the headers in the reponse before returning it to your script _(or not)_. For POST, PATCH, DELETE, that could be problematic, so it sends a preflight request to check the headers first. – blex May 26 '21 at 20:15
  • Right, a GET request with no additional options does not trigger a preflight OPTIONS request that can be used to ensure the actual request complies with the CORS policy. Instead, the actual request is just pushed through. What I'm not understanding, and what I was asking, is why I'm getting CORS-related errors when this is not a request that requires validation against CORS. – Matt May 26 '21 at 20:17
  • _"when this is not a request that requires validation against CORS."_ Any response from another origin will be validated. Whether it's in a preflight request, or in the GET request itself. It will always require validation from the browser. The only reason the browser will make a preflight request in case of a PUT, POST, PATCH, DELETE is that it does not want to risk altering anything on the server. In case of a GET, it simply makes the request, and still decides whether or not it should pass the response it received to your script, based on the headers – blex May 26 '21 at 20:19
  • 1
    You should probably read https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS – Thomas Sablik May 26 '21 at 20:24
  • 1
    @blex Tying this back to my specific question, let me make sure I understand. You're saying *any* request (but in my case, requests that do not require a preflight OPTIONS) to a different origin will fail if the server's response does not include an 'Access-Control-Allow-Origin' header? – Matt May 26 '21 at 20:27
  • That's what I was trying to say, yes – blex May 26 '21 at 20:30
  • No, the GET requests won't fail but the responses are not returned to the browser/app. The request is sent to the server. A PUT request actually fails. The request is not sent. Only the OPTIONS request is sent and the PUT is blocked. – Thomas Sablik May 26 '21 at 20:39

2 Answers2

2

why I'm getting CORS-related errors when this is not a request that requires validation against CORS.

Even if a request doesn't need a preflight CORS check, it will still get a CORS check.

For example, if you run in the console

var xhr = new XMLHttpRequest;
xhr.open("GET", "https://www.mozilla.org/en-US/");
xhr.send();

in the network tab, you will be able to click into "Response" and see the response, but you will still get

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.mozilla.org/en-US/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

The reason there is no pre-flight is because a GET request isn't supposed to modify anything, whereas other types of requests do, so the browser first does a "safe" check, before even allowing the real request to hit the server.

dave
  • 62,300
  • 5
  • 72
  • 93
  • Thank you. I thought a preflight OPTIONS request was a prerequisite to a request being blocked across origins. I didn't know that a standard GET request without a preflight OPTIONS could be blocked simply because the server's response does not include an `Access-Control-Allow-Origin` header. Can you help me explain why my same `fetch` request works in Chrome 90, but not FF? Is it due to the issue here? https://stackoverflow.com/a/15734032/209113 – Matt May 26 '21 at 20:37
  • Oh lol, I wasn't aware it worked in Chrome. I would double check that https security certificate is trusted (seems unrelated, but trust me), and if that doesn't work disable any plugins you have installed in firefox (sometimes adblockers cause issues like this). Otherwise I have no idea – dave May 26 '21 at 21:31
0

The mode in fetch determines how CORS is managed for a certain request when the resource being requested is from a different origin. The possible modes are "cors", "no-cors" and "same-origin", with "cors" being the default mode (1).

Therefore, even a "simple request" with fetch triggers the CORS protocol.

Setting mode to "no-cors" solves this, but be aware that with "no-cors"(1):

  • prevents JavaScript from reading the response
  • is useful for resources that don't have to be processed with JavaScript, like those that need to be cached or embedded as elements (<img/> or <iframe/>) on the webpage (1, 2)
  • requests are still made and responses are still received

More about this in this StackOverflow answer from @sideshowbarker♦

Advena
  • 1,664
  • 2
  • 24
  • 45