Understanding CORS, Cookies, and Cross‑Domain Solutions for Frontend Development
This article explains the fundamentals of cross‑origin restrictions, cookies, and same‑origin policy for frontend developers, demonstrates common CORS errors with sample code, and presents practical solutions—including iframe/postMessage, JSONP, WebSocket, and CORS configurations on servers such as Node.js and Nginx—to enable secure and reliable cross‑domain communication.
As a frontend developer, you are likely familiar with the pain points of cross‑origin requests and cookie handling. This article shares practical solutions for these issues across different business scenarios, explaining the underlying principles so that similar problems can be resolved efficiently.
Example of a problematic code snippet that triggers a CORS error:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>browser-safe-sandbox</title>
</head>
<body>
<div>browser-safe-sandbox</div>
<script>
console.log('浏览器安全沙箱')
const xhr = new XMLHttpRequest()
xhr.open('get','http://localhost:8090')
xhr.send()
</script>
</body>
</html>Running this code in a browser produces a CORS error because the request originates from http://localhost:5500 and attempts to access http://localhost:8090 without the required Access‑Control‑Allow‑Origin header.
Same‑origin policy requires that protocol, domain, and port all match. It protects user privacy by preventing a site (e.g., B.com) from reading cookies or other sensitive data stored by another site (e.g., A.com) after the user logs in.
Cookies are small pieces of data stored by the server in the browser and sent with subsequent requests to the same server, typically used for session management. Sharing login state across multiple sub‑domains can be achieved by setting cookies on a common parent domain.
Scenario: unified login across five systems
Encapsulate a common login component and embed it via iframe in each system.
Pass a returnUrl parameter to redirect back after successful login.
The login request goes to sso.account.com , which sets cookies for both .account.com and .browser.com .
Subsequent requests from chrome.browser.com carry these cookies, enabling shared authentication.
Logout must clear the cookies on all related domains.
Cross‑domain solutions
iframe + postMessage : Use window.postMessage for cross‑document communication. Example:
// Parent window sends a message
let win = window.open('http://a.jd.com', 'name');
win.postMessage('Hello JD!', 'http://a.jd.com');
// Child window replies
window.opener.postMessage('Hello JOY!', 'http://b.jd.com');
window.addEventListener('message', (event) => {
console.log(event.source);
console.log(event.origin);
console.log(event.data);
}, false);
window.addEventListener('message', getMessage);
function getMessage(event) {
event.source.postMessage('Hello JD JOY!', '*');
}AJAX alternatives : JSONP – works by inserting a script tag; only GET requests. WebSocket – full‑duplex communication that bypasses same‑origin restrictions. CORS – standard HTTP‑header based solution.
JSONP example :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONP跨域请求</title>
</head>
<body>
<script>
function jsonpCallback(result) {
console.log("服务端响应数据", result);
}
</script>
<script src="http://localhost:8090/jsonp?cb=jsonpCallback"></script>
</body>
</html>Or using jQuery:
$.ajax({
url: "http://localhost:8090/jsonp",
dataType: 'jsonp',
success: function(data) {
console.log("服务端响应数据", data);
}
});WebSocket provides bidirectional communication. Example request headers:
GET /chat HTTP/1.1
Host: server.jd.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://a.jd.comCORS (Cross‑Origin Resource Sharing) uses HTTP headers such as Access-Control-Allow-Origin and Access-Control-Allow-Credentials to allow browsers to access resources from other origins. Simple requests (GET, HEAD, POST with limited headers) are sent directly; non‑simple requests trigger a preflight OPTIONS request.
Node.js server example for a simple CORS response:
const http = require('http');
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5500');
res.setHeader('Access-Control-Allow-Credentials', true);
res.end('CORS');
});
server.listen(7080, 'localhost', () => {
console.log('7080 server success');
});For a non‑simple request, the server must also handle preflight headers:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, {
'Access-Control-Allow-Origin': 'http://localhost:5500',
'Access-Control-Allow-Headers': 'Custom-Head',
'Access-Control-Allow-Methods': 'POST, PUT, GET, OPTIONS'
});
res.end('CORS');
});
server.listen(7080, 'localhost', () => {
console.log('7080 server success');
});NGINX can also handle CORS globally:
# Wide‑open CORS config for nginx
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}While NGINX offers a quick solution, using a wildcard * for Access-Control-Allow-Origin reduces security; more complex scenarios may require a gateway layer for fine‑grained control.
JSONP vs. CORS
JSONP works only with GET requests and has compatibility advantages but lacks error handling and poses security risks.
CORS is a standardized, robust solution supporting all HTTP methods, proper error callbacks, and fine‑grained resource authorization.
Conclusion
CORS is the future‑proof approach for cross‑domain communication, yet depending on the environment (e.g., internal networks) simpler methods like JSONP or iframe/postMessage may still be appropriate. Choose the solution that matches the complexity and security requirements of your project.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.