同源策略
源
在一个网址的控制台输入window.origin或者location.origin可以查看网站源,就是协议+域名+端口。
如果两个网址的协议、域名、端口是一样的,就是同源的。
注意:https://www.baidu.com与https://baidu.com是不同源的
同源策略定义
浏览器规定,一个网站只能在同源中获取数据,不可以获取另外的源的数据,不可以跨域。(请求可以成功,但是不能获取数据)
注意,是网站运行的路径,就算是从其他源引用来的js程序,也不可以访问引用源的数据。
为什么需要同源策略
1.浏览器无法区分不同的请求,这样就无法区分恶意的数据盗取,不同的请求只有referer是不一样的。
2.如果没有同源策略,浏览器就完全无法保证数据的安全性,任何人都可以访问任何网站的数据。
几个问题
1.同ip不一定是同源,因为可以公用一个服务器
2.子级别的域名也不是同源,因为可以公用一个域名
3.为什么可以使用script或者link来引用css、js数据呢?
因为我们只是把数据加载到页面上,我们没有获取数据的内容(使用jsonp获取),类似于我们玩游戏,但是不能知道游戏的源码。(加上CORS就可以获取数据)
跨域
CORS(Cross-origin resource sharing)跨源资源共享
在服务器的http响应头中加入响应首部字段 Access-Control-Allow-Origin(setHeader),其值为允许跨域的网址(协议、域名、端口)。
如果要开放所有网站跨域,那么就得先获取请求的origin字段的值,将其添加到响应首部字段 Access-Control-Allow-Origin的内容中。
//对百度开放response.setHeader('Access-Control-Allow-Origin','https://www.baidu.com');//对所有开放response.setHeader('Access-Control-Allow-Origin',request.headers['referer']);//或者response.setHeader('Access-Control-Allow-Origin','*']);
在服务器中进行如上设置后,浏览器会根据请求头中的referer来判断是否允许跨域。
JSONP(P—padding)
JSONP的定义与用法
因为ie的低版本不支持,因此使用JSONP。
需要注意的是JSONP与JSON没有关系。
之前提过,我们可以使用script标签引用js文件,但是没有获取js的内容,但是我们可以将数据放在引用的js中,然后再获取它。
例如我们有一个包含数据的js文件
window.xxx = [
{"name":"朋友名1"},
{"name":"朋友名2"}
]
这样再执行这个js文件的时候,原本的js引擎中就会给window加上一个全局变量xxx,里面包含了一个数据,这样我们就通过执行js的方法获取到了跨域数据,但我们并没有拿到实际js的内容。
当然,我们也可以通过函数的方法来获取数据。不过我们需要再原js引擎中预先定义一个接收函数。
//引用的js文件,data为我们的需要的数据
window.xxx(data)
//页面的js程序
let script=document.createElement('script');
script.src=url;
document.body.appendChild(script);
window.xxx=function (data){result = data;}//这其实是一个跨域的回调函数,被其他js文件回调了
通过如上的操作我们就将数据通过函数赋值给了result变量,这样我们就可以在原本的js引擎中获取并操作跨域数据。
JSONP的优缺点
优点
1.支持ie
2.可以进行跨域
缺点
1.因为JSONP是通过script,因此不能像AJAX一样获取精准的状态码readystate和request.status,以及header
2.因为JSONP是通过script,所以JSONP只能支持get方法,不能支持post
JSONP的优化(callback优化回调函数名)
使用上述的JSONP可能会出现问题,即引用js文件定义的变量名和函数名可能会冲突,那么如何解决呢。
答案是通过url的查询参数,使用callback(例:http://qq.com/index.html?callback=参数),在服务器通过request.query获取参数,然后将request.query替换JSONP文件的占位符,这样就可以使用各种奇怪的变量、函数名了。
为什么要叫做JSONP
从上面的过程中看出,只要我们将数据放在js中,就可以进行跨域操作,那么为什么要叫做JSONP呢。
因为最初是想要解决访问json数据的问题,因此就命名为了JSONP,padding的来源是因为
window.xxx = [
{"name":"朋友名1"},
{"name":"朋友名2"}
]
观察如上代码,我们引用的js文件其实大部分就是json数据,padding指的是填充了的意思,指的是引用的js内容是填充过的json数据。
因此,我们需要注意的是,只要是js支持的数据格式,我们都可以使用JSONP的方法来进行跨域操作,而不只是局限于json数据。
JSONP的问题
JSONP的问题就是引用的js文件可以被任何页面引用,因此可以在服务器中对referer进行检查
//引用的js文件,data为我们的需要的数据
window.xxx(data)
//页面的js程序
let script=document.createElement('script');
script.src=url;//这里这里
window.xxx=function (data){result = data;}//这其实是一个跨域的回调函数,被其他js文件回调了
上面代码中,设置src的地址,在引用的时候会给服务器发请求,因此可以在服务端进行检查,对请求的referer进行检查,是我们希望的网站发来的请求,才给予正确的JSONP文件。
