The CORS (Cross-Origin Resource Sharing) mechanism
CORS (Cross-Origin Resource Sharing) Mechanism
Cross-Origin Resource Sharing (CORS) is the core mechanism in modern web development for handling cross-origin requests. It enables secure data interaction between different origins through HTTP header fields, overcoming the limitations imposed by the traditional same-origin policy on cross-origin access.
Same-Origin Policy and Cross-Origin Issues
The same-origin policy is the most fundamental security mechanism in browsers, requiring that scripts can only access resources from the same origin as the current page. The definition of "same origin" requires identical protocol, domain, and port. For example:
https://example.com
andhttps://api.example.com
are different origins (different subdomains)http://localhost:3000
andhttp://localhost:8080
are different origins (different ports)https://example.com
andhttp://example.com
are different origins (different protocols)
When a frontend attempts to make a cross-origin request, the browser will intercept the response and throw an error. This is particularly common in the development of frontend-backend separated applications.
How CORS Works
CORS enables cross-origin communication by adding specific header fields to HTTP requests and responses. The entire process is divided into two types:
- Simple Requests: Meet all the following conditions:
- Methods are GET, HEAD, or POST
- Only include safe header fields (Accept, Accept-Language, etc.)
- Content-Type is
application/x-www-form-urlencoded
,multipart/form-data
, ortext/plain
fetch('https://api.example.com/data', {
method: 'GET',
headers: {
'Content-Type': 'text/plain'
}
});
- Preflight Requests: When the conditions for a simple request are not met, the browser first sends an OPTIONS request for preflight:
fetch('https://api.example.com/data', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
},
body: JSON.stringify({key: 'value'})
});
Server-Side CORS Configuration
The server needs to set the correct response headers to allow cross-origin access. Below are common configuration examples:
Node.js Express Example
const express = require('express');
const app = express();
// Basic CORS configuration
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
// CORS configuration with credentials
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://client.example.com');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
// Preflight request handling
app.options('*', (req, res) => {
res.sendStatus(200);
});
Nginx Configuration Example
location /api/ {
add_header 'Access-Control-Allow-Origin' '$http_origin';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
}
Common CORS Header Fields
Header Field | Description | Example Value |
---|---|---|
Access-Control-Allow-Origin | Allowed origin | * or https://example.com |
Access-Control-Allow-Methods | Allowed HTTP methods | GET, POST, PUT |
Access-Control-Allow-Headers | Allowed request headers | Content-Type, Authorization |
Access-Control-Allow-Credentials | Whether to allow sending credentials | true |
Access-Control-Expose-Headers | Response headers accessible to the client | X-Custom-Header |
Access-Control-Max-Age | Preflight request cache time (seconds) | 86400 |
Credentials and CORS
When requests need to include cookies or HTTP authentication information, credential-related settings must be configured:
// Client-side
fetch('https://api.example.com/user', {
credentials: 'include'
});
// Server-side response headers
Access-Control-Allow-Origin: https://client.example.com
Access-Control-Allow-Credentials: true
Note: When using credentials, Access-Control-Allow-Origin
cannot be the wildcard *
and must specify a specific domain.
Common Issues and Solutions
-
Preflight Request Failure:
- Ensure the server correctly handles the OPTIONS method
- Check
Access-Control-Allow-Methods
andAccess-Control-Allow-Headers
configurations
-
Response Headers Not Exposed:
- Use
Access-Control-Expose-Headers
to expose custom headers
- Use
-
Caching Issues:
- Set an appropriate
Access-Control-Max-Age
to reduce preflight requests
- Set an appropriate
-
Cross-Origin Cookie Issues:
- Ensure both
withCredentials
andAccess-Control-Allow-Credentials
are set to true - Cookies need to have
SameSite=None
andSecure
attributes
- Ensure both
Practical Application Scenarios
Cross-Origin API Calls
async function fetchCrossOriginData() {
try {
const response = await fetch('https://api.thirdparty.com/data', {
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
}
});
if (!response.ok) throw new Error('Network response was not ok');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch error:', error);
}
}
Cross-Origin Web Fonts
Cross-origin fonts in HTML also require CORS:
<style>
@font-face {
font-family: 'MyFont';
src: url('https://cdn.example.com/fonts/myfont.woff2') format('woff2');
font-display: swap;
}
</style>
The server needs to add CORS headers for font files:
Access-Control-Allow-Origin: *
Security Considerations
-
Avoid overly permissive CORS policies:
- Do not use
Access-Control-Allow-Origin: *
in production - Whitelisting is better than wildcards
- Do not use
-
Protect sensitive operations:
- Critical APIs should be restricted to specific origins
- Combine with other security measures like CSRF tokens
-
Preflight request caching:
- Set a reasonable
Access-Control-Max-Age
to balance security and performance
- Set a reasonable
Alternative Solutions Comparison
When CORS is not applicable, consider other cross-origin solutions:
- JSONP (GET requests only):
function handleResponse(data) {
console.log(data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);
- Proxy Server:
// Frontend requests same-origin proxy
fetch('/api-proxy/data', {
method: 'POST',
body: JSON.stringify({query: 'value'})
});
// Server-side request forwarding
app.post('/api-proxy/data', async (req, res) => {
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(req.body)
});
const data = await response.json();
res.json(data);
});
- WebSocket:
const socket = new WebSocket('wss://api.example.com/ws');
socket.onmessage = (event) => {
console.log('Message:', event.data);
};
Debugging Tips
-
Browser Developer Tools:
- Check CORS-related requests and response headers in the Network panel
- Pay attention to CORS error messages in the console
-
Testing Tools:
- Use cURL to verify server response headers:
curl -I -X OPTIONS https://api.example.com/data \ -H "Origin: https://client.example.com" \ -H "Access-Control-Request-Method: POST"
-
Common Error Message Analysis:
No 'Access-Control-Allow-Origin' header
: Missing necessary response headersCredentials mode requires 'Access-Control-Allow-Credentials'
: Credential configuration mismatchMethod PUT is not allowed
: Method not in the allowed list
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn