一 同源策略
- 如果两个url的协议,域名,端口号完全一致,那么这两个url就是同源的。
- 浏览器规定,如果js运行在源A里,那么就只能获取源A的数据,不能获取源B的数据,即不允许跨域。
- 浏览器这样设计的目的是保护用户的隐私。
- 假如浏览器没有不允许跨域的规定。那么正常请求页面里的js和黑客网页里的js发的请求几乎没有区别(referer有区别),如果后台开发者没有检查referer,那么就完全没区别。所以,如果没有同源策略,任何页面都能偷服务器的数据。虽然检查referer可以避免该问题,但万一没有检查呢?因此浏览器应该主动预防这种偷数据的行为。总之,浏览器为了用户隐私,设置了严格的同源策略。
- 同源策略,不同源的页面之间,不准互相访问数据。
- 黑客跨域请求时,请求一般发成功了,但是拿不到响应,因为浏览器不给数据给它。
二 为什么可以跨域使用CSS,JS和图片等?
同源策略限制的是数据访问,我们引用CSS,JS和图片的时候,其实 并不知道其内容,我们只是在引用。
三 使用CORS实现跨域
- 问题根源
浏览器默认不同源之间不能互相访问数据,但是源A和源B其实都是自己的网站,此时就想要两个网站互相访问。 - 使用CORS(Cross-origin resource sharing)。如果要共享数据,需要提前声明。源B可以在响应头里面标注源A可以访问。Access-Control-Allow-Origin:源A地址。
- IE 6789都不支持CORS
四 使用JSONP实现跨域
- 在跨域的时候,由于浏览器不支持CORS,必须使用其他的方法跨域。同时,虽然不能跨域获取数据,但是可以跨域引用js呀,让js包含数据就好了。
- 源A请求源B的一个js文件,这个js文件会执行一个回调,回调里面就会用到源A想要的源B中数据。
- 回调的名字可以是源A随机生成的,源A把这个名字作为callback参数的值传给源B,源B会把这个函数再次返回给源A并执行这个函数。
//源A想要跨域访问源B
//源A中使用jsonp
function jsonp(url) {
return new Promise((resolve, reject) => {
const random = "specialString" + Math.random();
window[random] = (data) => {
resolve(data);
};
const script = document.createElement("script");
script.src = `${url}?callback=${random}`;
script.onload = () => {
//下载完引用的js后,删除script标签,否则页面会变臃肿
script.remove();
};
script.onerror = () => {
reject();
};
document.body.appendChild(script);
});
}
jsonp("源B的url").then((data) => {
console.log(data);
},(err)=>{
console.log(err);
});
//源B中服务器中相应的处理代码
if (path === "/xxx") {
if (request.headers["referer"].indexOf("源A的url") === 0) {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
const string = `window['{{xxx}}']({{data}}) `;
const data = fs.readFileSync("源B服务器上存放数据的路径").toString();
const string2 = string
.replace("{{data}}", data)
.replace("{{xxx}}", query.callback);
response.write(string2);
response.end();
} else {
response.statusCode = 404;
response.end();
}
}
- 优点:兼容IE;可以跨域。
- 缺点:由于是script标签,因此读不到ajax那么精确地状态,不知道状态码是什么,也不知道整个响应的头是什么,只知道成功或失败;由于它是script标签,所以只能发get请求,不支持post;谁都可以访问js文件,因此必须做referer检查。