I am developing a Vue3 app with Vite as the bundler. The app is served from localhost:5173
. The app communicates with an Express.js API, which is served from localhost:3000
. This is the request code:
const req = await fetch("http://localhost:3000/api/book", {
method: "POST",
body: JSON.stringify({ bookId: 4 })
}).then(res => res.json())
This is working. But when I add a Content-Type
header, I get a CORS error:
const req = await fetch("http://localhost:3000/api/book", {
method: "POST",
headers: {
"Content-Type": "application/json"
}
body: JSON.stringify({ bookId: 4 })
}).then(res => res.json())
Access to fetch at 'http://localhost:3000/api/book' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
To get around this, I followed the Vite docs for enabling CORS, and here is the updated vite.config.js
:
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
allowedHeaders: ["Content-Type", "Authorization"],
preflightContinue: true
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})
But the error persists. How do I fix this?
I found the problem, so I would like to post an answer in case someone faces the same problem.
Apparently, the problem is that Vue is sending a preflight request before the actual request, and only if this request succeeds, then Vue will send the actual request.
The preflight request was failing not because Vite was blocking cross-origin requests (it allows such requests by default), but rather because the Express server was blocking cross-origin requests. This causes the preflight request to fail together with the subsequent request.
The solution is to enable CORS on the Express server. For my case, since I am only doing it in development, I allowed all origins:
import express from 'express'
import cors from 'cors'
const app = express()
app.use(cors())