前端(AngularJS + 靜態頁面)部署在 https://frontend.com,後台 API 部署在 https://api.backend.com。前端需調用 GET /api/dict/items 獲取下拉選項數據,瀏覽器攔截跨域請求。
Spring Boot 示例:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://frontend.com") // 或 "*" 生產環境請具體域名
.allowedMethods("GET", "POST", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true) // 若需攜帶 Cookie
.maxAge(3600);
}
}
Nginx 反向代理層面也可統一添加:
add_header 'Access-Control-Allow-Origin' 'https://frontend.com';
add_header 'Access-Control-Allow-Credentials' 'true';
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,Authorization';
if ($request_method = 'OPTIONS') { return 204; }
$http.get('https://api.backend.com/api/dict/items') 直接工作,瀏覽器自動發送 Origin、處理 OPTIONS 預檢。
@GetMapping("/api/dict/items")
public MappingJacksonValue getItems(@RequestParam(required=false) String callback) {
List<DictItem> list = dictService.getItems();
MappingJacksonValue value = new MappingJacksonValue(list);
if (StringUtils.hasText(callback)) {
value.setJsonpFunction(callback); // 返回 callback([...])
}
return value;
}
$http.jsonp('https://api.backend.com/api/dict/items', {
jsonpCallbackParam: 'callback' // 默認 callback=JSON_CALLBACK
}).then(function(resp) {
$scope.items = resp.data;
});
| 維度 | CORS | JSONP |
|---|---|---|
| HTTP 方法 | 全部 | 僅 GET |
| 安全性 | 支持 Credentials、CSRF 防護 | 易受 XSS、無法攜帶 Cookie |
| 瀏覽器支持 | IE10+、所有現代瀏覽器 | IE6+、所有 |
| 後端改造 | 添加 Filter/配置 | 需包裝回調函數 |
$http.jsonp 要求響應 Content-Type: application/javascript,否則解析失敗。allowCredentials(true) 時,allowedOrigins **不能為 "*"**,必須指定具體域名。nginx proxy_pass 同域代理。現代項目**首選 CORS**,JSONP 仅作極少數舊環境兼容。