EN/CH Mode
BRUCE_FE Interview Notes - What is CORS? How to Fix CORS Issues?
In-depth analysis of Cross-Origin Resource Sharing (CORS) working principles, common errors and solutions. Master core CORS knowledge for frontend interviews, including various methods to solve cross-origin issues.
EN/CH Mode
Lazy to read articles? Then watch videos!
What is CORS?
Cross-Origin Resource Sharing (CORS) is a browser security mechanism used to control resource requests between different origins (domains, protocols, or ports). Simply put, it's like 'border control' between websites, determining which external resources can be accessed.
For example: Suppose you're browsing the website https://shopping.com, and this website needs to fetch product data from https://api.shopping.com. Although they look similar, because the domains are different, the browser will treat it as a 'cross-origin request' and block this access by default.
This is like you being in one store (frontend website) wanting to get products from another store (API server), but you need explicit permission from the other party. If the API server doesn't say 'I allow shopping.com to access my resources', the browser will block this request.
⚠️ Definition of Same-Origin:
Two URLs must have the same protocol (http/https), domain, and port to be considered same-origin. Like neighbors living in the same building.
- 1. https://example.com and https://api.example.com are not same-origin (different subdomains, like different buildings on the same street)
- 2. http://example.com and https://example.com are not same-origin (different protocols, like walking vs driving to the same location)
- 3. https://example.com and https://example.com:8080 are not same-origin (different ports, like different floors in the same building)
CORS Working Mechanism
CORS has two main request types: simple requests and preflight requests.
Type | Characteristics | Process | Use Cases |
---|---|---|---|
Simple Request | • GET/HEAD/POST methods • Basic headers • Simple Content-Type | Send request directly with Origin header | Simple form submissions, basic GET requests |
Preflight Request (Mainstream usage) | • Special HTTP methods • Custom headers • Special Content-Type like JSON | 1. Send OPTIONS request first to inquire 2. Server responds with permission 3. Then send actual request | Modern API requests, JSON data exchange, authenticated requests |
In modern web development, preflight requests are the mainstream case, because most API requests use JSON format and custom headers, which all trigger the preflight mechanism.
// Preflight Request
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://example.com
Access-Control-Request-Method: POST // Even simple method (POST)
Access-Control-Request-Headers: Content-Type, X-Custom-Header // But custom headers trigger preflight
// Preflight Response
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, X-Custom-Header
Access-Control-Max-Age: 86400 // Preflight result cache time (seconds)
Common CORS Errors
Access to fetch at 'https://api.example.com' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Most common CORS error, indicating the server has not set the Access-Control-Allow-Origin header.
Access to fetch at 'https://api.example.com' from origin 'https://example.com' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
Server has not allowed the requested HTTP method in Access-Control-Allow-Methods.
Access to fetch at 'https://api.example.com' from origin 'https://example.com' has been blocked by CORS policy: Request header field X-Custom-Header is not allowed by Access-Control-Allow-Headers in preflight response.
Server has not allowed the requested custom header in Access-Control-Allow-Headers.
Methods to Solve CORS Issues
1. Backend CORS Header Configuration
The most standard solution is to properly configure CORS headers on the backend server:
// Node.js Express Example
const express = require('express');
const app = express();
// Configure CORS middleware
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://example.com'); // or use * to allow all origins
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', 'true'); // Allow credentials
// Handle preflight requests
if (req.method === 'OPTIONS') {
return res.status(204).end();
}
next();
});
// Or use cors package
const cors = require('cors');
app.use(cors({
origin: 'https://example.com',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}));
2. Using Proxy Server
In frontend development environments, you can configure a proxy server to forward requests:
// webpack dev server proxy configuration
module.exports = {
// ...
devServer: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
}
}
}
// Next.js proxy configuration
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
]
},
}
3. Using Backend Relay Server
Using Route Handlers as a relay server to forward requests in Next.js 15:
This method works because the same-origin policy only applies to browser-to-server requests, while server-to-server requests are not restricted by CORS.
When our Next.js app acts as a relay server, the browser only communicates with the same-origin Next.js server, which then forwards requests to third-party APIs and returns responses to the frontend, thus bypassing CORS restrictions.
// app/api/proxy/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
try {
// Fetch data from third-party API
const response = await fetch(
`https://api.example.com/data?${searchParams}`
);
const data = await response.json();
// Return data to frontend
return NextResponse.json(data);
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch data' },
{ status: 500 }
);
}
}
4. Other Solutions
- JSONP (only for GET requests):Leverages the fact that script tags are not restricted by same-origin policy, but only supports GET requests and has lower security.
- Browser Extensions:Can use CORS browser extensions to temporarily disable CORS during development, but only suitable for development environments.
- Reverse Proxy:Use reverse proxy servers like Nginx, Apache to forward requests.
CORS Best Practices
1. Security First
- Avoid using * to allow all origins, explicitly specify allowed domains
- Only allow necessary HTTP methods and headers
- Use Access-Control-Allow-Credentials carefully
2. Performance Optimization
- Set appropriate Access-Control-Max-Age to cache preflight results
- Avoid unnecessary preflight requests by using simple request format
3. Development Convenience
- Use proxies or browser extensions in development environment
- Must properly configure CORS headers in production environment
🔥 Common Interview Questions
(1) What is CORS? Why do browsers need same-origin policy?
Answer: CORS is a browser security mechanism that allows servers to declare which websites can access their resources. The same-origin policy is like a firewall between websites, limiting data access between different websites.
Dangers without same-origin policy:
Malicious site(evil.com) User's bank site(bank.com)
| |
| User visits malicious site |
| while logged into bank |
| |
|-- Try to read bank data --X |
| |
| Browser blocks request |
| (Same-origin protection) |
Without the same-origin policy, when you log into a bank website and then visit a malicious site, the malicious site might secretly read your bank data or perform operations like transfers. CORS provides a secure standard mechanism when cross-origin access is needed.
(2) What are the best methods to solve CORS problems? What are the pros and cons of each?
Answer: Main methods to solve CORS:
Method | Pros | Cons |
---|---|---|
Backend CORS header configuration | Standard solution, flexible configuration | Requires backend cooperation |
Proxy server | Frontend can solve independently | Increases request complexity |
Backend relay server | Complete control over request handling | Requires maintaining additional services |
The most ideal solution is for the backend to properly configure CORS headers. If the API source cannot be modified, consider using a proxy or relay server.
(3) How to handle CORS issues in frontend-backend separated development environments?
Answer: CORS solutions in frontend-backend separated development environments:
1. Development environment proxy:
// Vite (vite.config.js/ts)
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, '')
}
}
}
});
2. Backend development environment configuration: Allow localhost domain access in development environment
3. Middle proxy server: If the frontend uses Next.js, consider using Next.js proxy functionality.
// app/api/proxy/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
try {
// Fetch data from third-party API
const response = await fetch(
`https://api.example.com/data?${searchParams}`
);
const data = await response.json();
// Return data to frontend
return NextResponse.json(data);
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch data' },
{ status: 500 }
);
}
}