CORS request blocked in locally opened html file
Asked Answered
N

10

39

I've started to write a HTML file which displays data with JavaScript. Since it shall be done as easy as possible I don't want to run nodejs oder any other local http server. I've just opened the HTML file in a browser (url is file:///home/visu/index.htm).

Everything is fine, till a jquery ajax request to a online API is done in the index.htm. The browser blocks the request with the message:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://x.x.x.x. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)."

How can I get rid of the problem without starting a local http server?

A possible solution is to start the browser with some "no security flags" or disable CORS with plugins, but this I've to do manually all the time so I don't like it.

Nut answered 20/1, 2018 at 23:20 Comment(1)
You can't get rid of the problem whether or not you start an HTTP server. The API you're accessing isn't meant to be used from a browser, so disabling the browser's security feature is the only way to make it work from a browser. Depending on your use case you should consider just running the script without a browser (use node.js, but no need to start a server).Equidistance
D
8

Not Possible By Design

CORS are always blocked when attempted from a file on disk (web pages using the file:// protocol). There is nothing you can do to make it work from a file. It is simply impossible.

The reasoning for this is that files on disk have no real "origin" to allow the backend server to determine the validity of the request. You can have a file for an issue tracking html on the same disk as a file for a blog html. The server cannot know which html requested the data (you can even have someone else's file shared via Dropbox with embedded javascript that may attempt to access your server's data when you open it - nobody expects a hacking attempt when they simply open a plain html file!!).

This is why no browser vendor will allow you do make CORS requests from a file.

You Need a Server

To make it work you will need a HTTP server. There are lots of options for this from installing Apache/Nginx on your machine to running dev servers like webpack-dev-server or local-web-server. As long as the protocol is http:// or https:// you are allowed to make CORS requests.

Once you have a server serving your html file you can configure CORS on your backend as usual.

Disepalous answered 8/7, 2022 at 4:42 Comment(1)
Thank you, local-web-server did the trick for me. It is a quick and easy solution. Install with $ npm install -g local-web-server and then serve your index.html file with $ ws --spa index.html.Transmit
L
6

When your browser will perform an AJAX request to a different server than the one hosting the current page, it first sends an OPTIONS HTTP message. In that message it sends the following header:

origin: http://my-web-server.com

And the backend server will respond with:

access-control-allow-origin: http://my-web-server.com

But, when you don't have a webserver, there is no address for your browser to put in that origin header. That's why your browser disallows you to do any AJAX request from a local file (maybe you can disable the browser's CORS security as someone mentioned in the comments, but that can put you at risk of malicious sites).

Another option

You can tell your browser to allow to connect from localhost to a backend if you change your backend to return the following header:

access-control-allow-origin: https://localhost:8888

And, you also need to tell your localhost server to serve your page in HTTPS instead of HTTP. Once both conditions are met, CORS validations won't fail.

Notice that to enable HTTPS you'll need to have a SSL cert and key, you can generate them with the following command:

openssl req -x509 -out localhost.crt -keyout localhost.key \
  -newkey rsa:2048 -nodes -sha256 \
  -subj '/CN=localhost' -extensions EXT -config <( \
   printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")

The source of that command and more information are found in this page from Let's Encrypt.

Logical answered 21/1, 2018 at 0:14 Comment(3)
is there anything we can do in the back-end server to allow request from local files ?Wristlet
yes, I updated my answer with an alternative solution.Logical
Another method was to use JsonP, however that means you are able to modified the host to connect toMomentum
G
5

As others have mentioned, you can host locally to avoid CORS exceptions. I found that I could do this with python's http module without having to install any further packages on my specific machine. YMMV:

# python3 -m http.server 8000 -d .../path/to/directory

Where 8000 is a port of your choosing.

Please note, that the documtentation for http.server states:

Warning http.server is not recommended for production. It only implements basic security checks.

In my case, this was more than sufficient for playing with some in browser graphics :).

Gildea answered 14/3 at 5:38 Comment(0)
S
2

On Firefox, you can install this addon: https://addons.mozilla.org/en-US/firefox/addon/cors-everywhere/ to disable CORS for the respective tab. Then, any request will also work on file:/// URIs. Be careful though!

Shrieve answered 15/12, 2022 at 14:34 Comment(1)
Even with this addon, I still get (for a related issue): Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///Users/bbarker/workspace/RustyRogue/wasm/rusty_rogue_bg.wasm. (Reason: CORS request not http).Hirokohiroshi
I
1

The solution by @Derzu to remove the type="module" from the JS script tag worked for me. I also moved the script tag to the bottom of my html because it is no longer deferred by default when it is not a "module".

To amplify for others, I found this thread when resolving this problem: I had built a simple HTML-CSS-JS project using Vite. It worked fine in Vite (using a server) but I needed to send it to a non-tech person so they could simply open the HTML file and have the project work. Initially, it did not work. The Network tab in the Dev Tools pointed to CORS errors in my style.css and index.js files as well as path errors to other assets. The steps that resolved this for me were:

  • Made a copy of a dist folder created by Vite. This copy was intended for opening an HTML file directly rather than spinning up a server.
  • Replaced absolute paths that Vite created, such as href="/assets/index-kJtgSd5e.css", with relative paths like href="assets/index-kJtgSd5e.css" by removing / in the beginning of the path. Did it for CSS and JS files in my HTML.
  • Removed crossorigin attribute from <link> tags for .js and .css.
  • As above, removed type="module" and moved the script tag toward the bottom of the body.
  • Also removed leading / in all other URLs in my HTML file.
  • Fixed the URLs in the CSS file to point to the correct assets. The fonts were now in the same folder as the CSS file but the images were in a different folder, so the paths to images turned into something like this: url(../images/[email protected]).

Note: my JS does not include any API requests, but it's still a CORS error so seems relevant.

Note2: I realized that I did not have to manually rename all the paths as above. Instead, this is done by vite.config.js:

export default {
 base: './',
}

However, with this config, I still had to fix the module and crossorigin attribute.

Isisiskenderun answered 31/1 at 12:35 Comment(0)
M
0

Either mock Ajax calls, or start web server with reverse proxy and HTTP rewriting configured, since I'm sure you don't want, or have not access to configure API server CORS headers.

If you don't want to mock ajax calls, then use either:

  1. node-http-proxy
  2. nginx - if you don't have nodejs and you don't want to install it.
Mayoralty answered 21/1, 2018 at 0:51 Comment(2)
Hi, have you read the "without starting a local http server" in the OP question ?Acnode
Yes I did! My answer still stands since CORS browser policy is applied even on file:// protocol. And since you can not change HTTP headers "on you filesystem", then the only option is some kind of reverse proxy or webserver that should serve that file for you.Mayoralty
S
0

If you are importing your javascript file using the type module:

<script type="module" src="code.js"></script>

Remove the type module, like that:

<script src="code.js"></script>

If you aren't using the type module, and it is still giving CORS error, the solution is to copy and paste all the .js files into your html file. So, instead of using the loading the js file, open the tag and add the code inside it, to your .html file. Example:

<html>
<head>
    <script>
        // Place your js code here. Just the code, not the file path.
        // Many files can be placed here.
    </script>
</head>
</html>

Obs: The best solution is still to create a local server, but this is a work around solution.

Scathe answered 2/9, 2023 at 2:0 Comment(0)
Y
0

You can't because for some reason the local file system is deemed as "not a server" essentially. Even though I would argue that local files which load from local files would in my opinion be fine. You can, however trivially use a script to act as a localhost server:

Just do something like this:

https://funprojects.blog/2021/04/11/a-web-server-in-1-line-of-bash/

Young answered 16/1 at 20:12 Comment(0)
J
-1

When making a fetch request with custom headers, including authentication tokens, it's crucial to correctly set up your request options. Additionally, dealing with CORS (Cross-Origin Resource Sharing) requires server-side configuration to allow requests from different origins, but there are also client-side considerations, especially during development.

Here's how you can structure your fetch request with custom headers:

    async function sendRequest(endpoint, payload, method) {
  try {
    const response = await fetch(endpoint, {
      method: method, // e.g., 'POST'
      mode: 'no-cors', // Use this for development/testing if facing CORS errors
      headers: {
        'Content-Type': 'application/json',
        'x-auth': 'YOUR_AUTH_TOKEN', // Custom header for your auth token
      },
      body: JSON.stringify(payload), // Ensure payload is stringified
    });

    // Note: 'no-cors' mode will result in an opaque response, limiting access to response properties
    if (!response.ok && response.type !== 'opaque') {
      throw new Error(`Error: ${response.statusText}`);
    }

    // Handling opaque response here (limited access due to 'no-cors' mode)
    return response; // Adjust based on your needs
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}
Joist answered 6/2 at 4:9 Comment(0)
P
-3

If you can not set it up access-control-allow-origin, you can try this.

Use "callback" function if your data is not in same domain. And wrap your data "jsonCallback(" ... data ... ") as my example: http://www.ceducation.cz/akce-plnytext.json?short=1&callback=?

function jsonCallback(json) {
  $.each(json, function(key, val) {
    // your data is here
    console.log('date: ' + val.date);
    console.log('address: ' + val.address);
    console.log('---');
  });
}

$(document).ready(function() {

  $.getJSON("http://www.ceducation.cz/akce-plnytext.json?short=1&callback=?", function(data) {

  });

});

Working example

Plyler answered 21/1, 2018 at 0:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.