24.跨域 手写 JSONP
跨域的产生原因
同源策略:浏览器出于安全考虑,限制不同源的页面间资源交互。
同源定义:协议(http/https)
、域名(www.example.com)
、端口(8080)
三者完全一致。
触发跨域的场景:
AJAX
请求不同源的 API
。
Web
字体、WebGL
等资源加载。
iframe
嵌入不同源页面并尝试通信。
跨域常见解决方案
方案一:CORS(跨域资源共享) 原理:服务端通过响应头声明允许的跨域请求来源、方法及头部。
Access-Control-Allow-Origin: https://www.example.com // 允许的源(或 * 表示所有)
Access-Control-Allow-Methods: GET, POST, PUT // 允许的请求方法
Access-Control-Allow-Headers: Content-Type, X-Token // 允许的请求头
Access-Control-Allow-Credentials: true // 允许携带 Cookie
方案二:反向代理 原理:通过同源的服务端代理转发请求,避开浏览器限制。 开发环境:使用 Webpack
的 devServer.proxy
或 Vite
的 server.proxy
。
生产环境:通过 Nginx
配置反向代理。
方案三:JSONP 原理:利用 <script>
标签不受同源策略限制的特性,通过回调函数获取数据。
function jsonp(url, callbackName) {
const script = document.createElement("script");
script.src = `${url}?callback=${callbackName}`;
document.body.appendChild(script);
}
// 服务端返回:callbackName({ data: ... });
window.handleData = (data) => {
console.log("Received:", data);
};
jsonp("https://api.example.com/data", "handleData");
方案四:WebSocket 原理:WebSocket 协议不受同源策略限制。
const socket = new WebSocket("wss://api.example.com");
socket.onmessage = (event) => {
console.log("Data:", event.data);
};
方案五:postMessage
原理:postMessage
方法不受同源策略限制,可用于不同源的页面间通信。
// 父页面
window.frames[0].postMessage("Hello", "https://child.com");
// 子页面(iframe)
window.addEventListener("message", (event) => {
if (event.origin !== "https://parent.com") return;
console.log("Received:", event.data);
});