JSONP请求

form img(只能发get请求) 都可以发请求

什么是JSONP

JSONP(JSON with Padding) 是 json 的一种使用模式,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。

请求方:ry.com 这个网站的前端程序员(浏览器)
响应方:king.com 这个网站的后端程序员(服务器)

  1. 请求方 创建 script,src 指向 响应方,同时传一个查询参数 ?callbackName=xxx
  2. 响应方 根据 查询参数 callbackName,构造形如
    1. xxx.call(undefined,’你要的数据’)
    2. xxx(‘你要的数据’)
      这样的响应
  3. 浏览器接收到响应,就会执行 xxx.call(undefined,’你要的数据’)
  4. 那么 请求方就知道了他要的数据

这就是 JSONP

行业约定

  1. callbackName -> callback
  2. xxx -> 随机数 ry13242345325325

引用代码如下

1
2
3
4
5
6
7
8
9
$.ajax({
url: 'http://king.com:8002/pay',
dataType: 'jsonp',
success: function (response){
if(response === 'heihei'){
amount.innerText = amount.innerText - 1
}
}
});

以下是一个 【付款】 网站

首先,将 index.js,index.html,db 文件里面的内容复制

index.js

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]

if(!port){
console.log('请指定端口号好不啦?\nnode server.js 8888 这样不会吗?')
process.exit(1)
}

var server = http.createServer(function(request, response){
var parsedUrl = url.parse(request.url, true)
var pathWithQuery = request.url
var queryString = ''
if(pathWithQuery.indexOf('?') >= 0){ queryString = pathWithQuery.substring(pathWithQuery.indexOf('?')) }
var path = parsedUrl.pathname
var query = parsedUrl.query
var method = request.method

/******** 从这里开始看,上面不要看 ************/

console.log('含查询字符串的路径\n' + pathWithQuery)

if(path === '/'){
var string = fs.readFileSync('./index.html','utf8')
var amount = fs.readFileSync('./db','utf8')
string = string.replace('&&&amount&&&',amount)
response.setHeader('Content-Type','text/html; charset=utf-8')
response.write(string)
response.end()
}else if(path === '/style.css'){
var string = fs.readFileSync('./style.css','utf8')
response.setHeader('Content-Type','text/css; charset=utf-8')
response.write(string)
response.end()
}else if(path === '/main.js'){
var string = fs.readFileSync('./main.js','utf8')
response.setHeader('Content-Type','application/javascript;')
response.write(string)
response.end()
}else if(path === '/pay'){
var amount = fs.readFileSync('./db','utf8')
var newAmount = amount - 1
fs.writeFileSync('./db',newAmount)
response.setHeader('Content-Type','application/javascript;')
response.statusCode = 200
response.write(`
${query.callback}.call(undefined,'heihei')
`)
response.end()
}else{
response.statusCode = 404
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write('找不到对应的路径,你需要自行修改 index.js')
response.end()
}

/******** 代码结束,下面不要看 ************/
})

server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)

JSONP 精髓

1
${query.callback}.call(undefined,'heihei')

index.html

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
<!DOCTYPE html>
<html>
<head>
<title>付款</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js
"></script>
</head>
<body>
<h5>余额<span id="amount">&&&amount&&&</span></h5>
<button id="button">付款</button>
<script type="text/javascript">
$(button).on('click',function(){
$.ajax({
url : "http://king.com:8002/pay",
dataType : "jsonp",//数据类型为jsonp
success : function(response){
if(response === 'heihei'){
amount.innerText = amount.innerText - 1
}
}
});
})
</script>
</body>
</html>

db (此表示代码中的金额)

1
1000

接着,找到电脑中的 hosts 文件 (shift+command+G),输入 /etc/hosts 前往

shift+command+G
将 hosts 文件复制出来
找到hosts文件,复制出来
在 副本 hosts 文件,添加这两行。

1
2
127.0.0.1 ry.com
127.0.0.1 king.com

在副本最后添加
保存并替换以前 hosts 文件(放到以前 hosts 文件的位置)

我们在后台,分别运行以下代码(打开两个)

1
node index.js 8001 //程序参数
1
PORT=8001 node index.js //环境变量

node index.js 8001

1
node index.js 8002
1
PORT=8002 node index.js

node index.js 8002

在浏览器地址栏,输入 king.com:8002 即可

king.com:8002

为什么 JSONP 不支持 POST 请求?

  1. 因为 JSONP 是通过动态创建 script 实现的。
  2. 但是,动态创建 script 只能用 GET,不能用 POST 。

小总结:

1.form 得要个 submit 按钮,表单提交会刷新页面。  
2.那我们就用 img ,但是 img 只能知道成功和失败,不能知道更多的数据。  
3.那我们就用 script ,script 要让后端知道我们要执行的代码,那我们就要加 callback 参数,
后台就根据 callback 参数,构造出一个函数调用,然后把数据放到 第一个参数 里面,call 一下就好了。

script + callback参数 = JSONP