kit
kit copied to clipboard
CORS errors during server rendering
Describe the bug
When fetching an endpoint using CORS from a +page.js file, SvelteKit throws a CORS error when trying to render the page on the server, such as during development mode or prerendering for production. CORS doesn't seem to make sense in this context, since the fetch request is being performed on the server, which has no origin.
This seems related to https://github.com/sveltejs/kit/issues/7441, but that issue involved +page.server.js files. In this issue, we want to perform the fetch on the client AND the server (during SSR/prerendering).
Reproduction
https://stackblitz.com/edit/cors-error-during-server-render-repro?file=src%2Froutes%2Ftest%2F%2Bpage.js
Using the client-side navigation from / to /test fetches data on the client perfectly fine, but doing a browser navigation/reload on the /test page throws a CORS error on the server. Errors are also thrown when trying to run a build.
Logs
No response
System Info
StackBlitz WebContainer
Binaries:
Node: 16.14.2 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 7.17.0 - /usr/local/bin/npm
npmPackages:
@sveltejs/adapter-auto: ^1.0.0 => 1.0.0
@sveltejs/kit: ^1.0.0 => 1.0.1
svelte: ^3.54.0 => 3.55.0
vite: ^4.0.0 => 4.0.3
Severity
serious, but I can work around it
Additional Information
No response
I do experience this issue on your Stackblitz reproduction, but when I download the project and run it locally, I do not.
SvelteKit intercepts fetch requests that could come from either the server or the client, and "simulates" CORS on the ones that run on the server. It's a good idea, because otherwise people could be thinking they're all good when their site works in SSR mode, but then when a user navigates and the same request is done as a CORS fetch via the browser, it could fail.
But in your situation, that check is falsely asserting that the simulated CORS check has failed. But... only on StackBlitz. There are some differences to how Undici and StackBlitz web containers handle fetches...
Here's SvelteKit making an SSR fetch via Undici:
{
"user-agent": "undici",
"accept": "*/*",
"accept-encoding": "br, gzip, deflate",
"accept-language": "*",
"origin": "http://127.0.0.1:5173",
"sec-fetch-mode": "cors",
"x-forwarded-for": "47.196.22.77",
"x-forwarded-host": "sveltekit.free.beeceptor.com",
"x-forwarded-proto": "https"
}
And here's Firefox making one through StackBlitz:
{
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0",
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"accept-language": "*",
"cache-control": "no-cache",
"origin": "https://corserrorduringserverrenderrepro-f5o4.w-corp.staticblitz.com",
"pragma": "no-cache",
"referer": "https://corserrorduringserverrenderrepro-f5o4.w-corp.staticblitz.com/",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "cross-site",
"te": "trailers",
"x-forwarded-for": "47.196.22.77",
"x-forwarded-host": "sveltekit.free.beeceptor.com",
"x-forwarded-proto": "https"
}
But the weird thing is that both requests are getting the a "access-control-allow-origin": "*" response header... but the StackBlitz version thinks it is getting no access-control-allow-origin header.
I have the same exact issue on a GitPod repo. I needed to disable csrf in svelte.config.js in order to continue working on it, and will need to remember resetting it in production. I guess I could something like csrf: env.prod === 'dev', but it feels weird to disable it completely during development.
Perhaps an ORIGIN=... variable in the .env file could solve this?
It might be an issue with the test endpoint in the example since httpbin returns an access-control-allow-origin that matches the origin (or is *). When an endpoint returns a proper access-control-allow-origin that's set to a domain, SvelteKit throws an error during server rendering (in dev and build). When I was trying it on StackBlitz it gave an error with httpbin but that might be a different issue considering that the header should be set.
If someone knows of a test endpoint that sets an access-control-allow-origin that might be a better test endpoint.
It seems that the browser removes the access-control-allow-origin prior to handing it to the user's JavaScript - when doing response.headers.get('access-control-allow-origin'), it doesn't show up. I assume that Stackblitz and GitPod either have no control to forward these headers (because they can't access them either) or are removing them before passing it on.
We can't fix this without removing the sensible checks to ensure things run on the client and server the same, so I think the best we can do is document this. A workaround (which SvelteKit will warn you about, but you can ignore it in this case) is to use the global fetch in these cases.
I have the same exact issue on a GitPod repo. I needed to disable
csrfinsvelte.config.jsin order to continue working on it, and will need to remember resetting it in production. I guess I could something likecsrf: env.prod === 'dev', but it feels weird to disable it completely during development.Perhaps an
ORIGIN=...variable in the.envfile could solve this?
I am also developing on Gitpod and am running into this issue. I use the same workaround as @Haffi921.
I am facing same issue. During production there would be different hosts, event.url.origin matches to a k8s container and not the user facing hostname. This creates CORS on server side because event.url.origin is never going to match user facing hostname, which BE api would be accepting in the origin header.
We cannot use no-cors on server as universal fetch returns an empty body response which is not useful at all.
We need a way to set the initial event.url.origin which is going to be used on all the cors requests going forward. Or better would be to not use 'cors' during server side rendering.
@itssumitrai does the documentation below help resolve your issue? Does setting ORIGIN to your user facing hostname help?
https://kit.svelte.dev/docs/adapter-node#environment-variables-origin-protocolheader-and-hostheader
Any updates?