跨域的几种方式
1. 什么是跨域?
跨域: 就是不同域之间进行相互资源请求,也叫非同源策略请求。
例如:http://baidu.com 请求:http://taobao.com 即进行不同的域名下的资源调用。
注意:域名对应的IP地址也算是跨域操作;例:127.0.0.1 和 localhost 虽然对应,但是在地址栏中算两个域。
2. 为什么出现跨域?
浏览器在解析JavaScript出于安全方面的考虑,只允许在同域名下页面进行相互资源请求调用,不允许调用其他域名下的页面的对象;简单的理解就是 因为JavaScript同源策略的限制。
注意: 跨域并不是请求发不出去,请求能发出去,服务器能收到请求并正常返回结果,只是结果被浏览器拦截了,所以页面无法正常使用数据。
3. 什么是同源策略?
同源策略要求源相同才能进行正常的资源交互,即要求当前页面与调用资源的协议、域名、端口号 完全一致;只要有一个不同就是跨域。
参考如下图理解:
说明:
1、如果是协议和端口造成的跨域问题“前台”是无能为力的。
2、在跨域问题上,域仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。
4. 同源策略的限制
同源策略限制一个资源地址加载的文档或脚本来自另一个资源地址进行交互,这是浏览器的一个用于隔离潜在恶意文件的关键的安全机制。它的存在可以保护用户隐私信息,防止身份伪造等(读取Cookie)。
同源策略限制内容有:
1、Cookie、LocalStorage、IndexedDB等存储性内容
2、不允许进行DOM节点的操作
3、不能进行AJAX请求
5. 同源策略的天然支持跨域请求的特性属性
1、<img src="xxx" />
2、<link href="xxx" />
3、<script src="xxx" ></script>
6. 解决同源策略的方法
方法一:处理跨域的jsonp方法
JSONP原理
利用<script src="xxx">
元素的这个天然支持跨域的策略,网页可以得到从其他来源动态产生的JSON数据。JSONP请求一定需要对方的服务器做支持才可以。
JSONP和AJAX对比
JSONP和Ajax相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但Ajax属于同源策略,JSONP属于非同源策略(跨域请求)。
JSONP优缺点
JSONP优点是兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性。
原理图
JSONP的流程(以第三方API地址为例,不必考虑后台程序)
-
声明一个回调函数,其函数名(如fn)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。
-
创建一个
<script>
标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=fn)。 -
向服务器发请求,同时会把本地的一个函数传递给服务器
-
服务器接收到客户端请求后,需要进行特殊的处理:1.准备数据 data={…} 2.给客户端返回数据,把传递进来的函数名和它需要给你的数据拼接成一个字符串
func('+JSON.stringify(data)+')
-
返回数据,最后服务器把准备的数据通过HTTP协议返回给客户端,客户端再调用执行之前声明的回调函数(fn),对返回的数据进行操作。
jQuery的jsonp形式
JSONP都是GET和异步请求的,不存在其他的请求方式和同步请求,且jQuery默认就会给JSONP的请求清除缓存。
$.ajax({
url:"http://127.0.0.1:3001/user/list
dataType:"jsonp",
type:"get",//可以省略
jsonpCallback:"fn",//->自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略
jsonp:"jsonp",//->把传递函数名的那个形参callback变为jsonp,可省略
success:function(data){
console.log(data);}
});
方法二:处理跨域的CORS方法
CORS原理
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
CORS优缺点
CORS要求浏览器(>IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。
优点在于功能更加强大支持各种HTTP Method,缺点是兼容性不如JSONP。
只需要在服务器端做一些小小的改造即可:
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:POST,GET");
例如:网站 http://localhost:63342/ 页面要请求 http://localhost:3000/users/userlist 页面,userlist页面返回json字符串格 {name:‘Jackson’,gender:‘male’,career:‘singer’}:
//在服务器端设置同源策略地址
router.get("/userlist",function(req, res,next){
var user ={name:'Jackson', gender:'male', career:'singer'};
res.writeHeader(200,{"Access-Control-Allow-Origin":'http://localhost:63342'});
res.write(JSON.stringify(user));
res.end();
});
在响应头上添加 Access-Control-Allow-Origin 属性,指定同源策略的地址。同源策略默认地址是网页的本身。只要浏览器检测到响应头带上了CORS,并且允许的源包括了本网站,那么就不会拦截请求响应。
header("Access-Control-Allow-Origin:*");
// * :表示所有其他的域可以向当前域发送请求
//或者
header("Access-Control-Allow-Origin:http://test.com:80(相同默认不写)");
// http://test.com:80 表示指定具体的这个域可以向当前域发送请求。
//当然也可以指定多个特定域名,多个地址的话用逗号分隔即可。