前言
首先我们得先了解JSONP是怎么产生的。
最开始跨域请求数据没有现在方便,Ajax直接请求普通文件存在跨域无权限访问的问题,然后聪明的程序员想出了一套非官方的解决办法,程序员发现凡是带有“src”这个属性的标签都拥有跨域的能力,比如<·img>、<·iframe>、<·script>。
事实上早期的程序员也是这么干的,最后程序员们发现最好的解决办法就是——动态创建script标签发起请求,然后从后端拿到请求回来的数据进行处理,再然后把刚刚创建的script标签删掉,这就是JSONP的整套流程。做完这一切,在用户的角度是感觉不到动态创建script标签以及发送请求的,用户体验非常好,因此JSONP提供了一种各方都很满意的跨域解决方案。
页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="style.css">
<title>Title</title>
</head>
<body>
<h5>您的账务余额为<span id="amount">&&&amount&&&</span></h5>
<button id="button">汇款</button>
<script>
button.addEventListener('click', (e) => {
let script = document.createElement('script')
let name = 'json' + parseInt(Math.random() * 100000, 10)
window[name] = (e) => {
console.log(e)
if (e === 'success') {
amount.innerText = amount.innerText - 1
}
}
script.src = 'http://houduan.com:8002/pay?callback=' + name
document.body.appendChild(script)
script.onload = (e) => {
e.currentTarget.remove()
delete window[name]
}
script.onerror = (e) => {
alert('fail')
e.currentTarget.remove()
delete window[name]
}
})
</script>
</body>
</html>
服务器
var http = require('http')
var fs = require('fs')
var url = require('url')
// var port = process.argv[2]
var port = process.env.PORT || 8888
// 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 path = request.url
var query = ''
if(path.indexOf('?') >= 0){ query = path.substring(path.indexOf('?')) }
var pathNoQuery = parsedUrl.pathname
var queryObject = parsedUrl.query
var method = request.method
/******** 从这里开始看,上面不要看 ************/
console.log('HTTP 路径为\n' + path)
console.log('pathNoQuery', pathNoQuery)
if(path == '/'){
var string = fs.readFileSync('./index.html', 'utf8')
var amount = fs.readFileSync('./db.txt', 'utf8')//100
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 (pathNoQuery === '/pay'){
var amount = fs.readFileSync('./db.txt', 'utf8')
var newAmount = amount - 1
fs.writeFileSync('./db.txt', newAmount)
response.setHeader('Content-Type', 'application/javascript')
response.statusCode = 200
response.write(`
${queryObject.callback}.call(undefined, 'success')
`)
//JSON + 左右padding =JSONP 就是这个意思
//JSON: {
// "success": true,
// "left": ${newAmount},
// }
response.end()
}else{
response.statusCode = 404
response.setHeader('Content-Type', 'text/javascript; charset=utf-8')
response.write('找不到对应的路径,你需要自行修改 index.js')
response.end()
}
/******** 代码结束,下面不要看 ************/
})
server.listen(port)
console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)
JSONP:
请求方:qianduan.com 的前端程序员(页面)
响应方:houduan.com 的后端程序员(服务器)
1.请求方创建script,src指向响应方,同时传一个查询参数 ?callbackName=yyy
2.响应方根据查询参数callbackName,构造形如
(1)yyy.call(undefined, ‘你要的数据’)
(2)yyy(‘你要的数据’)
这样的响应
3.浏览器接收到相应,就会执行yyy.call(undefined,'你要的数据’)
4.那么请求方就知道了他要的数据
这就是JSONP
约定:
1.一般不用callbackName,约定用callback
2.一般不用,约定用随机数 例如:data589844959310093()
$.ajax({
url: 'http://houduan.com:8002/pay
dataType: 'JSONP'
success: function(response) {
if(response === 'success') {
amount.innerText = amount.innerText - 1
}
}
})
JQuery对其进行的封装,因为调用形式很像ajax,所以JQuery将JSONP封装进ajax中,但请注意!JSONP与ajax不一样!
- ajax:核心是通过XmlHttpRequest获取非本页内容
- JSONP:核心是动态添加<-script->标签来调用服务器提供的js脚本。