定义
同源策略
首先我们要了解什么是同源策略,来看看百度百科的解释:
同源策略,它是由Netscape提出的一个著名的安全策略。
现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。
当一个浏览器的两个tab页中分别打开百度和谷歌的页面
当一个百度浏览器执行一个脚本的时候会检查这个脚本是属于哪个页面的
即检查是否同源,只有和百度同源的脚本才会被执行。
总结的来说,由于浏览器安全限制,数据是不可以直接跨域请求的,包括不同的根域名、二级域名、或不同的端口,除非目标域名授权你可以访问。想要解决同源策略实现传输,就需要跨域。而跨域的方式有很多种,JSONP就是其中的一种。
具体想了解更多,可以看看阮一峰老师的文章,讲解的非常详细:
https://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
JSONP的产生
我们发现,Web页面上调用js文件时则不受是否跨域的影响,不仅如此,我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<\script>、<\img>、<\iframe>。
而有一种叫做JSON的纯字符数据格式可以简洁的描述复杂数据,并被原生js支持。
所以实现跨域的方案就出现了。我们可以调用跨域服务器上动态生成的js格式文件,也就是调用JSON文件,获取自己需要的数据。
后来逐渐形成了一种非正式的传输协议,也就是JSONP。该协议允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,客户端接收到响应后执行回调并且可以对数据进行各种需要的处理。
说到这里,我们来总结一下什么是JSONP:
通过动态创建script标签,其scr指向非同源的url,并传递一个callback参数给服务端,服务器返回一个以callback参数作为函数名的函数的调用和一系列参数,页面接收到响应后执行回调并对数据进行处理。
接下来我们就把JSONP的完整过程来实现一遍。
实现JSONP
首先,我们要有一个请求方和响应方,请求方是一个网页的前端,也就是浏览器,响应方是另一个网页的后台,也就是服务器,两个网页时不同源的。
这里我们假设浏览器页面显示着一个数字100和一个打钱
的按钮,服务器储存着页面显示的那个数字,要求在每按下打钱
按钮的时候,浏览器显示的数字减一,并且服务端储存这个减后的数字,在下一次打开的时候显示减后的数字。这是一个跨域向非同源网站的服务器发送请求和接收响应的过程。
请求方:http://fang.com:8001
响应方:http://zeng.com:8002
先写好html:
接着就是写前端部分代码main.js,实现点击之后发送请求改变数字:
button.addEventListener(
'click',(e)=>{
let script = document.createElement('script')//创建script标签
let functionName = 'fang' + parseInt(Math.random()*10000000,10)//设置调用函数名
window[functionName] = function(result){
if(result === 'success'){
amount.innerText = amount.innerText - 1
}else{
}
}
script.src = `http://zeng.com:8002/pay?callback${functionName} `
document.body.appendChild(script)//将能实现发送跨域请求的script标签插入html
script.onload = function(e){
e.currentTarget.remove()
delete window[functionName]
}
script.onerror = function(){
alert('fail')
e.currentTarget.remove()
delete window[functionName]
}
//完成传输后删除script标签
}
)
搭建好服务器,就可以实现功能了。这个就是一个利用JSONP发送跨域和响应的过程。
JSONP的优点与缺点
优点
- JSONP可以跨越同源策略,实现跨域传输,不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制
- JSONP兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
- 在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方
缺点
- 它只支持GET请求而不支持POST等其它类型的HTTP请求,因为script标签的scr只能进行GET请求
- 它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
- jsonp在调用失败的时候不会返回各种HTTP状态码。
- 缺乏安全性。假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的,那么所有调用这个jsonp的网站都会存在漏洞,这样的话危险就不止在一个域名下。