How to Solve CORS Errors: Practical Frontend and Backend Strategies
This article explains why browsers block cross‑origin requests due to the Same‑Origin Policy, then walks through six practical solutions—including CORS headers, JSONP, Nginx reverse proxy, API gateways, WebSocket, and postMessage—providing code examples for both frontend and Spring Boot backend configurations.
Many developers encounter CORS errors when the browser blocks a request that works fine with tools like Postman. The root cause is the browser's Same‑Origin Policy, which treats requests from different protocols, domains, or ports as potentially unsafe.
The policy considers any request that differs in protocol, domain, or port as cross‑origin and blocks it unless the server explicitly allows it.
fetch('http://api.xxx.com:8000/user')
.then(res => res.json())
.then(data => console.log(data)); // CORS error in browserTo resolve this, you need a cross‑origin solution that relaxes the browser's restrictions.
2 Solutions to CORS
2.1 CORS (Cross‑Origin Resource Sharing)
Applicable scenarios : front‑back separation projects, APIs used by multiple clients.
CORS is a W3C standard; the backend adds response headers to tell the browser which origins are allowed.
Backend code example (Spring Boot) :
@CrossOrigin(origins = "http://localhost:8080")
@GetMapping("/user")
public User getUser() { /* ... */ }
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}Key response headers :
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Methods: GET,POST
Access-Control-Allow-Credentials: true
Common pitfalls :
If allowCredentials(true) is used, allowedOrigins cannot be "*".
Complex requests (e.g., Content‑Type: application/json) trigger a pre‑flight OPTIONS request that must be handled.
2.2 JSONP
Applicable scenarios : legacy projects, GET‑only third‑party APIs (e.g., map services).
JSONP exploits the fact that <script> tags are not subject to CORS.
Frontend code :
function handleUserData(data) {
console.log("Received data:", data);
}
const script = document.createElement('script');
script.src = 'http://api.xxx.com:8000/user?callback=handleUserData';
document.body.appendChild(script);Backend code (Spring Boot) :
@GetMapping("/user")
public String jsonp(@RequestParam String callback) {
User user = new User("Tony", 30);
return callback + "(" + new Gson().toJson(user) + ")";
}Drawbacks :
Only GET requests; limited query length.
Susceptible to XSS attacks.
2.3 Nginx Reverse Proxy
Applicable scenarios : production deployment, micro‑service gateway.
Let Nginx add CORS headers so the browser sees the request as same‑origin.
Nginx configuration example :
server {
listen 80;
server_name localhost;
location /api {
proxy_pass http://api.xxx.com:8000;
add_header 'Access-Control-Allow-Origin' 'http://localhost:8080';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
}
}Frontend then requests /api/user, which Nginx forwards to the real backend.
2.4 API Gateway (e.g., Spring Cloud Gateway, Kong)
Similar to Nginx but integrated into the micro‑service layer.
Spring Cloud Gateway configuration :
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "http://localhost:8080"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true2.5 WebSocket
Applicable scenarios : real‑time communication such as chat or live market data.
WebSocket handshake is not restricted by CORS.
Frontend code :
const socket = new WebSocket('ws://api.xxx.com:8000/ws');
socket.onmessage = event => {
console.log('Received message:', event.data);
};Backend code (Spring Boot) :
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/ws");
}
}2.6 postMessage
Applicable scenarios : communication between a page and an iframe or popup.
Use window.postMessage to exchange data across origins.
// Parent page
const childWindow = window.open('http://child.com');
childWindow.postMessage('I am your parent', 'http://child.com');
// Child page
window.addEventListener('message', event => {
if (event.origin !== 'http://parent.com') return; // verify source
console.log('Received from parent:', event.data);
});Summary
Development : use CORS annotations for quick fixes.
Production : prefer Nginx or API gateway to centralize CORS handling.
Legacy projects : JSONP works but should be avoided for new code.
Real‑time scenarios : adopt WebSocket.
Security : avoid wildcard * in Access-Control-Allow-Origin; use explicit whitelist.
The root cause of CORS issues is the browser’s same‑origin policy, not the HTTP protocol itself.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
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.
