小知识,大挑战!本文正在参与“ 程序员必备小知识 ”创作活动
本文同时参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金
一、Jsonp为跨域而生
为什么会出现跨域问题?
🙋♀️出于浏览器的同源策略限制。
什么是源?
🙋♀️源(origin)就是协议(protocol),主机(host)和端口号(port)。
同源策略是浏览器的行为,是浏览器最核心也最基本的安全功能。浏览器的同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。它拦截的是前端请求回来的数据,即请求发送了,服务器响应了,但是因为同源策略无法被浏览器接收。
同源策略需要同时满足以下三点要求:
1)协议相同 2)域名相同 3)端口相同
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同时,需要跨域才能成功访问。
二、Jsonp与Json有个P关系
Jsonp 全称是Json with Padding,但你可千万别以为它和Json有关系。
Json是一种数据交换格式,而Jsonp是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。打个形象的比方:Json是地下党们用来书写和交换情报的“暗号”,而Jsonp则是把用暗号书写的情报传递给自己同志时使用的接头方式。看到没?一个是描述信息的格式,一个是信息传输的协议。
由于浏览器的同源策略搞事情,虽然后端确确实实已经给前端返回Json数据,但浏览器一旦发现不是同源页面的资源,于是它就会将传过来的响应报文丢掉🙄。
但是机智的人类发现在页面上直接发起一个跨域的ajax请求是不可以的,但是,在页面上引入不同域上的js脚本却是可以自由访问的。例如可以在自己的页面上使用<img src=""> 标签来随意显示其他域上的图片:
于是,人类想到了利用这个“漏洞”就可以很好的解决跨域请求:🤔后端不返回Json格式的数据,而是返回一段调用某个函数的js代码,供前端来调用和处理,实现跨域。
那怎么在后端设法把数据装进js格式的文件里呢?
众所周知,后端一般给前端返回json数据,而使用Jsonp的特殊之处就在于前端会传递一个callback参数(key)给后端,接着后端返回数据时会将这个callback参数的值(value)作为函数名来包裹住json数据,最终返给前端的就是一段js代码了,这样就巧妙地解决了跨域的问题✨。
三、手撕Jsonp 实现跨域请求实例
基于
vue引入Jsonp实现开源接口的跨域
npm 安装 vue-Jsonp
npm install vue-Jsonp --save
src/main.js 中添加
import {VueJsonp} from 'vue-Jsonp'
Vue.use(VueJsonp)
vue组件中使用Jsonp:
1.直接使用 Jsonp
1️⃣在src/main.js引入vue-resource
vue-resource是一个通过
XMLHttpRequrest或Jsonp技术实现异步加载后端数据的Vue插件它提供了一般的
HTTP请求接口,并且提供了全局方法和vue组件实例方法。
import VueResource from 'vue-resource'
Vue.use(VueResource)
2️⃣在vue文件中就可以直接用Jsonp
this.$http.jsonp("https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
{
params: {//请求参数
wd:'张杰'
},
jsonp:'cb', //回调参数key
//jsonpCallback:"test" //回调函数value
}).then(function(res){
console.log("this.$http.jsonp-res:",res)
},
function(){
console.log("抱歉无法调取")
}
)
2.引入jQuery,搭配 ajax 使用Jsonp
1️⃣在vue文件中直接引入jQuery库
import $ from 'jquery'
2️⃣在ajax中引入jsonp
$.ajax({
url:"http://suggestion.baidu.com/su?",
type:"get",
dataType:"jsonp",
data:{
wd:"王菲",
},
jsonp:'cb', //回调函数参数
jsonpCallback:"test" //回调函数值
}).then(res=>{
console.log("ajax-res:",res);
})
🎈一些解释
怎么告诉后端我要用哪个方法所获得的数据呢❓
前端与后端商量好,前端通过定义jsonp的值,从而与后端的某个函数关联起来。
听我细细说来~
使用Jsonp进行跨域时,请求的url地址后面会自动带上一个callback=xxx传给后端,后端需要对返回给前端的json数据做处理,callback是回调函数参数,xxx即是回调函数名称,回调函数名传到后端后,会被拿来包裹住要返回给前端的json数据,最终返回给前端的数据是xxx(json)的形式。而前端将会用script的方式处理返回数据,来对json数据做处理,以此完成一个有效的Jsonp请求。
此处的callback可通过jsonp来自定义,xxx可通过jsonpCallback来自定义。
jsonp: 回调函数的参数,是与后端约定好的参数,必须与后端保持一致。不另外定义jsonp的话,一般默认为jsonp:'callback'。
jsonpCallback: 回调函数名,用来包裹住json数据,不另外定义的话,这个参数的值往往是随机生成的。
下面我画了一张图表示了Jsonp请求的全过程👇
四、使用Jsonp的一些其他话
-
使用
Jsonp跨域,是需要后端配合的,设置callback,需要后端给前端传的是Jsonp格式(也就是一段js脚本)的数据,才能完成跨域请求。关于协商:
jsonpCallback就是你告诉后端最终应该生成哪个方法来包裹住返回给前端的json数据,jsonp是用来处理后端字段名不是默认值callback的情况,可以自定传递给后端的字段名。举栗说明:
https://xxx.com/ip?<jsonp>=<jsonpCallback>假设💦前端发出的请求是:
https://xxx.com/ip?callback=cb,一般参数名即callback这个字段名是后端固定、前端默认的,所以你和后端要协商的就是 callback 的值,也就是这里的cb,但是这完全取决于后端。因为有可能在一些后端没有实现
callback这个参数,他只能返回固定的函数名比如runCode,即返回如下runCode(1234)那就没办法协商,你只能按照他的来,你就要在前端处理
runCode这个函数。如果后端实现了允许自定义返回处理的函数,但是它固定的参数名就叫
callback,这时候你就可以传递一个jsonp: 'callback'和jsonpCallback: 'runCode',注意jsonp默认值就是callback,所以也可以省略。如果后端实现了允许你自定义
jsonpCallback,但是它接受一个等同于callback的参数,但是他不叫callback,而是叫cb,那这时候你就可以传递jsonp: 'cb',同时传递jsonpCallback: runCode,最终构成了<https://xxx.com/ip?cb=runcode>。后面两种情况,你都可以不传递
jsonpCallback参数,而是由jQuery自动生成,你最终只需要在success里面就可以处理。 -
Jsonp只支持get请求,就算前端指定成post方式,会自动转为get方式。而后端如果设置成post方式了,那Jsonp请求跨域就失效了。Jsonp是一种【请求一段js脚本,把执行这段脚本的结果当做数据】的玩法。1.拼接一个script标签,在请求的url中传入一个要执行的函数的方法名,从而触发对指定地址的get请求
2.后端对这个get请求进行处理,并返回字符串 “myCallback(‘response value’)”
3.前端script加载完之后,其实就是在script中执行myCallback(‘response value’)
4.是不是就完成了跨域的请求
5.是不是就是只能用get所以
Jsonp不会对后端代码或者内容做更改,因为它只能发送get请求 -
Jsonp是异步的前端发送请求给后端,在等待后端响应返回数据时:
同步——前端不能动,要一直等着后端的反馈。
异步——前端可以自由活动,可以先去执行别的方法。Jsonp动态创建一个script标签拼接一个回调函数,去后端找指定的函数返回数据,函数的执行是异步的。 -
使用
Jsonp跨域的优缺点优点:
①
Jsonp不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,Jsonp可以跨越同源策略;②
Jsonp的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持③ 在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分开了。我提供的
Jsonp服务只提供纯服务的数据,至于提供服务以后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,逻辑都可以使用同一个Jsonp服务。缺点:
①
Jsonp只支持GET请求,而不支持POST等其它类型的HTTP请求
②Jsonp只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
③Jsonp在调用失败的时候不会返回各种HTTP状态码。
④Jsonp安全性不够。假如提供Jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个Jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下,所以在使用Jsonp的时候必须要保证使用的Jsonp服务必须是安全可信的。
solo理解,如有不对的地方,欢迎指教~
参考资料: