Search code examples
javascriptrbrowsercorssvelte

CORS Error when using .page.js, but not .page.server.js to fetch external csv ressource with SvelteKit


There are many similar question, but none really made me understand this very basic problem in plain english.

I am trying to fetch the data from this csv file in my SvelteKit-Application.

I first tried to load it in a load-function in the +page.js file like this:

//+page.js
import Papa from 'papaparse';
export async function load({ fetch }) {
    const res = await fetch(
        'https://sites.ecmwf.int/data/climatepulse/data/series/era5_daily_series_2t_global.csv'
    ).then((r) => r.text());
    const { data } = Papa.parse(res, { header: true });
    return { data };

However, I'm getting this error on the server (my terminal where I started the dev-server)

Error: CORS error: No 'Access-Control-Allow-Origin' header is present on the requested resource at universal_fetch (<path....>node_modules/@sveltejs/kit/src/runtime/server/page/load_data.js:257:12) at process.processTicksAndRejections (node:internal/process/task_queues:105:5)

By what I understand what's happening here is that locahost is making the fetch-request to that ressource, but it's not allowed. Am I right in the assumption that I cannot do anything agains that, but the server where the file lives whould have to do change something in their settings?

When I put the same file in the +page.server.js, I can fetch the ressource as the request is coming from my node-server right? I then, can pass the data forward to the frontend right?

I know this is a really basic question, but it causes a lot of confusion for me. Especially because I just tried to read the file with R and the read_csv-function without any issues. Why is that working so smoothly, but the fetch on the frontend is not?


Solution

  • You pretty much answered your own question correctly. As read on MDN:

    For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, fetch() and XMLHttpRequest follow the same-origin policy. This means that a web application using those APIs can only request resources from the same origin the application was loaded from unless the response from other origins includes the right CORS headers.

    But it is still only a browser mechanism, which means that if a resource is public or unprotected, it can still be succesfully requested by another server. Yes, when it says No 'Access-Control-Allow-Origin' header is present on the requested resource it means that you whoever owns the resource you're accessing has to put that header on the response, especifying who they trust.

    In Svelte the +page.js a load function runs both on the server and in the browser, returning last from the client while the +page.server.js only runs on the server, that's why you get the CORS error. One way you can return something only from the server in the +page.js is putting your code inside an if (!globalThis.window) statement to make sure you're not in the browser environment. You can also use the browser environment variable from Svelte instead of the globalThis.window, but (just to be clear) the right way of returning from the server really is the +page.server.js.