How to Solve Cross-Origin Issues: CORS, JSONP, Nginx Proxy & More
This article explains why browsers enforce the Same‑Origin Policy, illustrates common CORS errors, and provides practical solutions—including CORS headers, JSONP, Nginx reverse proxy, API gateways, WebSocket, and postMessage—along with code examples and best‑practice tips for both development and production environments.
1 What is the cross-origin problem?
Many developers encounter CORS issues: the backend API works in Postman but the browser blocks it.
The browser enforces the Same‑Origin Policy, treating requests from different protocol, domain, or port as cross‑origin.
Example: frontend at http://localhost:8080, backend at https://api.xxx.com:8000. If any of protocol, domain, or port differ, the browser blocks the request.
<code>// Frontend code (http://localhost:8080)
fetch('http://api.xxx.com:8000/user')
.then(res => res.json())
.then(data => console.log(data));
// Browser console error: Access to fetch from 'http://localhost:8080' has been blocked by CORS policy...</code>Therefore a cross‑origin solution is needed.
2 Solutions to cross-origin problems
2.1 CORS (Cross‑Origin Resource Sharing)
Applicable scenarios : front‑end/back‑end 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) :
<code>// Method 1: Direct annotation (single endpoint)
@CrossOrigin(origins = "http://localhost:8080")
@GetMapping("/user")
public User getUser() { ... }
// Method 2: Global configuration
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600);
}
}
</code>Key response headers :
Access-Control-Allow-Origin: http://localhost:8080 (allowed origin)
Access-Control-Allow-Methods: GET,POST (allowed methods)
Access-Control-Allow-Credentials: true (allow cookies)
Pitfalls :
If allowCredentials(true) is used, allowedOrigins cannot be "*"; you must specify explicit domains.
Complex requests (e.g., Content‑Type: application/json) trigger a preflight 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 same‑origin restrictions; the server returns a JavaScript callback.
Front‑end code :
<code>function handleUserData(data) {
console.log("Received data:", data);
}
// Dynamically create script tag
const script = document.createElement('script');
script.src = 'http://api.xxx.com:8000/user?callback=handleUserData';
document.body.appendChild(script);
</code>Backend code :
<code>@GetMapping("/user")
public String jsonp(@RequestParam String callback) {
User user = new User("Tony", 30);
return callback + "(" + new Gson().toJson(user) + ")";
}
</code>Output :
<code>handleUserData({"name":"Tony","age":30})</code>Drawbacks :
Only GET requests, limited parameter length.
Susceptible to XSS attacks because the client must trust third‑party script.
2.3 Nginx reverse proxy
Applicable scenarios : production deployment, micro‑service gateway.
Let Nginx handle CORS so the browser sees all requests as same‑origin.
Nginx configuration example :
<code>server {
listen 80;
server_name localhost;
location /api {
# Forward to real backend
proxy_pass http://api.xxx.com:8000;
# Solve cross‑origin
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';
}
}
</code>Frontend then requests /api/user , which Nginx proxies to the real backend.
Advantages :
Zero code changes in front‑end or back‑end.
Can hide real API endpoints for added security.
2.4 Gateway layer unified handling
Applicable scenarios : API gateways such as Spring Cloud Gateway, Kong.
Similar to Nginx but integrated into the gateway, adding CORS configuration directly.
Spring Cloud Gateway config :
<code>spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "http://localhost:8080"
allowed-methods: "*"
allowed-headers: "*"
allow-credentials: true
</code>2.5 WebSocket
Applicable scenarios : real‑time communication (chat, stock quotes).
WebSocket handshake is HTTP, then upgrades to a persistent connection without CORS restrictions.
Front‑end code :
<code>const socket = new WebSocket('ws://api.xxx.com:8000/ws');
socket.onmessage = (event) => {
console.log('Received message:', event.data);
};
</code>Backend code (Spring Boot) :
<code>@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyWebSocketHandler(), "/ws");
}
}
</code>2.6 PostMessage
Applicable scenarios : communication between a page and an iframe or popup.
Use window.postMessage to transfer data across windows.
Parent page code :
<code>const childWindow = window.open('http://child.com');
childWindow.postMessage('I am your parent', 'http://child.com');
</code>Child page code :
<code>window.addEventListener('message', (event) => {
if (event.origin !== 'http://parent.com') return; // verify source
console.log('Received message from parent:', event.data);
});
</code>Summary
Simple dev : use CORS annotations.
Production : prefer Nginx or gateway for unified handling.
Legacy projects : JSONP works but avoid long‑term reliance.
Real‑time scenarios : use WebSocket.
Security first : avoid wildcard origins; whitelist exact domains.
Remember, CORS is a browser behavior, not an HTTP protocol issue; if Postman works but the browser fails, the problem lies on the front‑end side.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.