关于跨域的技巧可以分为 iframe 跨域和 API 跨域。
JSONP 跨域
JSONP 全称:JSON with padding,可用于解决老版本浏览器的跨域数据访问问题。
由于 web 页面上请求的 js 文件不受同源策略的限制,所以可以用 script 标签进行跨域请求:
首先前端需要事先设置好回调函数,并作为 script 标签 src 属性的查询参数。
服务端接收到请求后,通过查询参数获取对调函数,并把数据作为回调函数的参数然后将其返回。
收到结果后因为是 script 标签,所以浏览器会当做脚本自动执行,从而达到跨域获取数据的目的。
jsonp 之所以能够跨域,关键在于页面调用 js 脚本是不受同源策略的影响,相当于向后端发起一条 http 请求,跟后端约定好函数名,后端拿到函数名,动态计算出返回结果并返回给前端执行 JS 脚本,相当于是一种 “动态 JS 脚本”。
// data.js 路由代码
const data = {
state: "success",
data: "test"
};
const callback = query.callback;
response.statusCode = 200;
response.setHeader("Content-Type", "application/javascript");
response.end(`${callback}(${JSON.stringify(data)})`);
// 前端代码
let callbackName = "jsonp" + parseInt(Math.random() * 1000000, 10);
window[callbackName] = function (result) {
console.log(result);
};
let script = document.createElement("script");
script.src = "http://localhost:8081/data.js?callback=" + callbackName;
document.body.appendChild(script);
script.onload = (e) => {
e.currentTarget.remove();
delete window[callbackName];
};
script.error = () => {
console.log("请求失败");
delete window[callbackName];
};
优点
- 它不像 XMLHttpRequest 对象实现的 Ajax 请求那样受到同源策略的限制。
- 兼容性很好,在一些古老的浏览器上也能很好的运行。
缺点
- 因为是 script 标签发请求,所以只支持 GET 请求。
CORS
CORS 是一个 W3C 的标准,全场是 “跨域资源共享”(Cross-origin resource sharing)它允许浏览器向跨源服务器发起 XMLHttpRequest 请求,从而克服了 ajax 只能同源使用的限制。
CORS 需要浏览器和服务器同时支持才可以生效,对于开发者来说,CORS 通信与同源的 ajax 通信吗,没有区别,代码是完全一样。浏览器一旦发现 ajax 请求资源,就会自动添加一些附加头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信了。
// data.js 路由代码
response.statusCode = 200;
response.setHeader("Content-Type", "text/html;charset=urf-8");
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
response.end("response data");
// 前端逻辑
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:8081/data.js", true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send();
关键在于设置了响应头 Access-Control-Allow-Origin,该值要与请求头中 Origin 一致才能生效,否则将跨域失败。
CORS 的优缺点
- 使用方便,更为安全。
- 支持 POST 请求。
- CORS 是一种新型的跨域解决方案,存在兼容性问题。
服务端代理
服务端代理,顾名思义,当你需要有跨域的请求操作时发送请求给后端让后端帮你代发请求,然后将获取的结果发送给你。
以请求 CNode 社区 社区的 api 为例。
// 后端逻辑
if (path === "/a.html") {
https.get("https://cnodejs.org/api/v1/topics", (res) => {
let data = [];
res.on("data", chunk => {
data.push(chunk);
});
res.on("end", () => {
response.setHeader("Content-Type", "application/json; charset=utf-8");
response.end(Buffer.concat(data).toString());
});
});
}
通过代码可以看出,当访问 http://localhost:8080/a.html
的时候,服务器收到请求,会代发你的请求到 https://cnodejs.org/api/v1/topics
最后将获取的数据发送给你。