前言
首先我们得先了解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=' + namedocument.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.urlvar query = ''if(path.indexOf('?') >= 0){ query = path.substring(path.indexOf('?')) }var pathNoQuery = parsedUrl.pathnamevar queryObject = parsedUrl.queryvar 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')//100string = 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 - 1fs.writeFileSync('./db.txt', newAmount)response.setHeader('Content-Type', 'application/javascript')response.statusCode = 200response.write(`${queryObject.callback}.call(undefined, 'success')`)//JSON + 左右padding =JSONP 就是这个意思//JSON: {// "success": true,// "left": ${newAmount},// }response.end()}else{response.statusCode = 404response.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/paydataType: 'JSONP'success: function(response) {if(response === 'success') {amount.innerText = amount.innerText - 1}}
})
JQuery对其进行的封装,因为调用形式很像ajax,所以JQuery将JSONP封装进ajax中,但请注意!JSONP与ajax不一样!
- ajax:核心是通过XmlHttpRequest获取非本页内容
- JSONP:核心是动态添加<-script->标签来调用服务器提供的js脚本。