瀏覽器同源策略限制 AJAX 跨域請求。現代應用首選 CORS(跨域資源共享),舊環境可用 JSONP 繞過限制。本文詳解兩種方案的實現原理與代碼實戰。
服務端響應頭添加 Access-Control-Allow-Origin,瀏覽器檢查匹配後允許跨域響應被 JavaScript 讀取。
// Java Servlet 示例
resp.setHeader("Access-Control-Allow-Origin", "https://127.0.0.1:8080"); // 指定域名
// 或通配符(不支持攜帶 Cookie)
resp.setHeader("Access-Control-Allow-Origin", "*");
// 支持憑證(Cookie/HTTP 認證)
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Origin", "https://127.0.0.1:8080"); // 不能用 *
// 預檢請求支持
resp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
resp.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
resp.setHeader("Access-Control-Max-Age", "3600");
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", true);
xhr.withCredentials = true; // 攜帶 Cookie
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
<script> 標籤不受同源策略限制。服務端返回可執行的 JavaScript 代碼,調用預約好的回調函數並傳遞數據。
// jQuery 封裝(推薦)
$.ajax({
url: "https://api.example.com/jsonp",
dataType: "jsonp", // 關鍵:啟用 JSONP
jsonp: "callback", // 回調參數名(默認 callback)
jsonpCallback: "handleData", // 自定義回調函數名
success: function(data) {
console.log(data);
}
});
// 原生實現
function loadJSONP(url, callbackName) {
var script = document.createElement('script');
script.src = url + (url.indexOf('?') > -1 ? '&' : '?') + 'callback=' + callbackName;
document.head.appendChild(script);
}
window.handleData = function(data) {
console.log('收到數據:', data);
};
loadJSONP('https://api.example.com/jsonp', 'handleData');
<?php
// PHP 示例
$callback = $_GET['callback'] ?? 'callback';
$data = ['code' => 200, 'msg' => 'success', 'data' => ['id' => 1, 'name' => 'test']];
header('Content-Type: application/javascript; charset=utf-8');
echo $callback . '(' . json_encode($data) . ');';
// Java Servlet 示例
String callback = req.getParameter("callback");
String json = "{\"code\":200,\"data\":\"test\"}";
resp.setContentType("application/javascript;charset=UTF-8");
resp.getWriter().write(callback + "(" + json + ");");
| 維度 | CORS | JSONP |
|---|---|---|
| HTTP 方法支持 | 全支持 (GET/POST/PUT/DELETE...) | 僅 GET |
| 請求體支持 | 支持 | 不支持 |
| 錯誤處理 | 完善 (onerror, status code) | 困難 (無狀態碼) |
| 安全性 | 高 (可控源、憑證) | 低 (腳本注入風險) |
| 瀏覽器支持 | IE10+ 完美 | 全瀏覽器 (含 IE6) |
| 適用場景 | 現代應用、REST API、需 POST | 舊瀏覽器、簡單 GET、第三方嵌入 |
Allow-Origin 白名單,避免 * 洩露敏感數據callback 參數格式(僅允許字母數字下劃線),防止 XSS