1. 什么是跨域
  2. JSONP的原理
  3. 在Jquery中使用JSONP
  4. 在vue-resource中使用JSONP
  5. 参考

JSONP

JSONP(JSON with Padding)是在早期浏览器不允许跨域的背景下,诞生的 一种通信方式

什么是跨域

前端获取数据一般都通过XMLHttpRequest发送请求,但有一定的限制
在CORS之前, 浏览器不允许通过XMLHttpRequest向不同于当前域名/端口/协议的地址发送请求
另外,这种(向不同域名)发送请求的行为通常称为"跨域"

例如

当前域名 http://www.example.com/foo
允许 http://www.example.com
允许 http://www.example.com/api/foo
禁止 https://www.example.com
禁止 http://bar.example.com
禁止 https://www.example.com:4000

JSONP的原理

虽然XMLHttpRequest禁止跨域,但部分HTML元素没有这个限制,例如img script iframe等
JSONP利用了script标签可以跨域的特点,通过script标签获取JSON数据
当后端接受请求后,动态返回一段函数调用格式的源代码文本.其中的函数名为url的callback参数值,函数参数为JSON数据
例如
执行如下代码

1
2
3
4
5
6
7
8
function foo(data) {
console.log(data)
}
// 创建一个script元素
var script = document.createElement('script')
// 设置资源地址,其中的callback参数就是将被回调的函数名
script.src = 'https://jsonplaceholder.typicode.com/todos/1?callback=foo'
document.body.appendChild(script)

当后端收到响应时,会返回如下数据
捕获.PNG
如上图所示,后端返回一段函数调用表达式,其中的函数名就是callback参数传入的foo,而参数是JSON格式的所需数据

在Jquery中使用JSONP

普通的json

1
2
3
4
5
6
7
8
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1',
dataType: 'json',
data: { foo: 'bar' },
success: function(response) {
console.log(response)
}
})

json发送的url
捕获.PNG
json接收到的数据
4.PNG
JSONP

1
2
3
4
5
6
7
8
9
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1',
jsonp: 'callback',
dataType: 'jsonp',
data: { foo: 'bar' },
success: function(response) {
console.log(response)
}
})

JSONP发送的url
2.PNG
参数callback后面的jQuery33...就是绑在success上的函数名

JSONP收到的数据
3.PNG

在vue-resource中使用JSONP

vue-resource除了支持get post等常见请求方式外,还支持JSONP
示例
捕获.PNG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<div id="app" v-show="todo.id">{{todo}}</div>
</template>

<script>
import Vue from 'vue'
import VueResource from 'vue-resource'
Vue.use(VueResource)
export default {
data() {
return { todo: {} }
},
methods: {
updateTodo() {
let url = 'https://jsonplaceholder.typicode.com/todos/1'
this.$http.jsonp(url).then(response => {
console.log(response)
this.todo = response.body
console.log(this.todo)
})
}
},
created() {
this.updateTodo()
}
}
</script>

如需更改callback名,则需添加'jsonp'参数
捕获.PNG

1
2
3
4
const url = 'https://c.y.qq.com/musichall/fcgi-bin/fcg_yqqhomepagerecommend.fcg'
this.$http.jsonp(url, {
jsonp: 'jsonpCallback'
})

参考

浏览器的同源策略 | MDN
不要再问我跨域的问题了 - 个人文章 - SegmentFault 思否