Search code examples
expresscorsvuejs3vite

Vite won't allow CORS (Vue3 application)


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?


Solution

  • 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())