什么是跨域
一个源的下的文档或脚本去访问别的源的资源,这是因为浏览器的同源策略,不同源页面之间,不准互相访问数据。
源
- 源=协议+域名+端口号(默认80端口不显示)
- window.origin或localtion.origin可以得到当前源
- 两个URL全部一致才为同源
同源策略
不同源的页面之间,不准互相访问数据。
举例:如果JS运行在源A内,那么就只能获取源A的数据,不能获取源B的数据,即不允许跨源。
限制的是数据访问,但可以引用内容(css,js,图片)
解决办法
CORS(跨域资源共享)
举例:运行在 http://domain-a.com 的JavaScript代码使用XMLHttpRequest来发起一个到 https://domain-b.com/data.json 的请求。
步骤
若要共享数据,在共享网站的响应头里写允许那个网站可以访问
header(Access-Control-Allow-Origin:'url')
JSONP
为了跨域的时候某些浏览器不支持CORS(比如IE就不支持),必须使用另一种方法来跨域。
于是网站可以请求一个JS文件,JS会执行一个回调,回调里面有我们的数据。
回调名字可以是随机生成随机数,然后作为callback的参数传给后台,后台会把函数返回并执行。
步骤
- A网站先将内容写到js内
- B网站用script标签引用js
- B网站事先定义window.xxx函数
window.xxx可以改些其他名字只要B网址定义的函数名和B网址里js执行的函数名是同一个
- B网站引用js执行window.xxx通过这个可以获取到数据
- 若script标签过多,可以删除
script.onload = () => {
script.remove();
};
等script标签加载完后删除
优点
- 兼容IE
- 可以跨域
缺点
- script标签读不到AJAX那么精确的状态(码和响应头),因为只用来监听onload和onerrfor
- script标签只能发送get请求(JSONP不支持POST)
JSONP封装
jsonp的函数名约定俗称为callback
function jsonp(url){
return new Promise((resolve,reject)=>{
const random = "JSONPCallbackName"+Math.random()
window[random]=data=>{
resolve(data)
}
const script = document.createElement("script")
script.src = `${url}?callback=${random}`
script.onload = ()=>{
script.remove()
}
script.onerror = ()=>{
reject()
}
document.body.appendChild(script)
})
}
jsonp('http://lz.com:5050/friend.js').then(data=>{
console.log(data)
})
在请求的时候可以通过headers["referer"]
来判断是否同源
if (path === "/friends.js") {
if (request.headers["referer"].indexOf("http://lz.com:5050") === 0) {
response.statusCode = 200;
response.setHeader("Content-Type", "text/javascript;charset=utf-8");
const string = `window['{{xxx}}']({{data}}) `
const data = fs.readFileSync("./public/friends.json").toString();
const string2 = string.replace("{{data}}", data).replace('{{xxx}}', query.callback);
response.write(string2);
response.end();
}