jsonp跨域到底是怎么一回事?

什么是跨域

1.浏览器的同源策略

       在了解浏览器同源策略之前我们要先知道什么是源(origin),源就是协议、域名、端口,所谓的同源也就是协议、域名和端口号均相同。同源策略是浏览器最核心、最基本的安全功能,非同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。一个页面在请求非同源页面的资源时,会被浏览器拒绝。同源策略的限制点主要在针对接口的请求和DOM操作上。
       问题来了,我们有时候不可避免地向不同源的站点请求资源,该怎么办呢?这就是我们常说的跨域,跨域的方法有很多,本文只针对jsonp一种展开。

2.浏览器为什么要有同源策略?

       浏览器的同源策略肯定不是没事找事故意为难开发人员,那么浏览器为什么要有这样一个同源策略呢?这要从同源策略的限制点说起,我们来看看假如没有同源策略的限制,会发生什么危险的情况。

a.我们的浏览器没有限制非同源的接口请求

       假如你想登陆你的网上银行给朋友转账,按照流程输入账号密码登陆成功。这时,你一不小心打开了一个恶意的钓鱼网站。你刚刚登陆的时候cookie是存在本地的,因为没有同源策略的限制,所以这个钓鱼网站暗地里就可以使用你刚刚的cookie向接口发送请求,这就相当于钓鱼网站登陆了你的网银账户,那后果不堪设想。这也就是所谓的CSRF(跨站请求伪造)攻击,但这在有同源策略防护的情况下是不会轻易发生的。

b.我们的浏览器没有限制访问非同源的DOM

       假如你还是想登陆你的网上银行给朋友转账,你一不小心进入了一个恶意的钓鱼网站,这个网站通过一个iframe引用原网站。你进入的页面表面上看起来跟原网站没有什么区别,你按照流程输入账号密码登陆。这时,因为我们的浏览器没有限制访问非同源的DOM,所以钓鱼网站只需要简单的getElementById(input)就可以轻易地得到你的账号密码,然后为所欲为。同样,这在有同源策略防护的情况下也是不会轻易发生的。
       由此可见,同源策略确实能规避一些危险。但不是说有了同源策略的保护,我们访问页面就可以高枕无忧了,只能说同源策略是浏览器给我们提供的最基本的防护机制,能一定程度上降低被攻破的可能。

什么是jsonp?

       上文提到了跨域的方法,jsonp是其中常见的一种。我们知道拥有src属性的标签都不受同源策略的限制,如</script>、</img>、</iframe>等,jsonp就是利用这个原理逐渐形成的一种非正式传输协议。
       我们都知道json数据格式可以简单地描述复杂数据,而且json被原生js完美支持(可以与js对象任意互相转换),那么如果服务端动态地将客户端需要的json格式的数据包装起来,客户端通过标签引入对应的js文件就可以获得需要的数据了。jsonp的核心过程就是用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住json数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
       这样看起来可能还是有点抽象,我们接下来直接看代码,“jsonp协议”到底是怎么做的。

jsonp具体是怎么做的?

       jsonp通过</script>的src属性,将远程的js文件引入并执行,也就是将一个js文件加到当前页面的里执行。
1.假如我们已知abc.com目录下有一个abc.js文件如下:

console.log("remote file");

def.com目录下有一个def.html页面如下:

<!DOCTYPE>
<html>
<head>
	<script type="text/javascript" src="http://abc.com/abc.js"></script>
</head>
<body>
</body>
</html>

       运行结果是def页面控制台输出remote file,这是最简单的jsonp跨域demo。

2.我们在def页面定义一个函数,在远程js文件里调用,然后引入远程js文件。abc.js文件如下:

a({"info":" jsonp跨域"});

def.html如下:

<!DOCTYPE>
<html>
<head>
	<script type="text/javascript">
		var a=function(data){
			console.log("远程js文件的数据是"+data.info);
		};
	</script>
	<script type="text/javascript" src="http://abc.com/abc.js"></script>
</head>
<body>
</body>
</html>

       很显然,def页面的控制台会输出远程js文件的数据是jsonp跨域。那么问题来了,我们怎么让远程js文件知道该调用哪个函数呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。
3.我们可能会想到,只要服务端的js文件是动态生成的就可以了呗,客户端可以传过去一个参数告诉服务端我想要一份“你来调用某个函数的js代码”,这样服务端就能响应客户端的要求返回需要的js代码了。
def.html如下:

<!DOCTYPE>
<html>
<head>
	<script type="text/javascript">
		var a=function(data){
			console.log("远程js文件的数据是"+data.info);
		};
		//定义js文件的地址
		var url="http://abc.com/abc.js?need=data&callback=a";
		//创建script标签并设置地址
		var script=document.createElement("script");
		script.setAttribute("src",url);
		//把script标签加入head
		document.getElementByTagName("head")[0].appendChild(script);
	</script>
</head>
<body>
</body>
</html>

       这样一来,我们看到url中有两个参数,need告诉服务端我请求的数据是data,callback告诉服务端我的回调函数是a,请你把need作为参数调用该函数。那么服务器将返回如下js代码:

a({"info": "jsonp跨域"});

ps:服务端的操作就是拼接一个字符串。


       现在就已经理解jsonp的原理了吧,剩下的就是处理获得的数据用于渲染或者交互啦。但本质上来说jsonp只能用于get方法不能用于post。




       以上是我对jsonp的理解,如有错误还请大牛指正,如有不同意见也欢迎质疑,希望对大家有所帮助,也希望同样在准备春招的朋友一切顺利。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值