jsonp原理javascript
因为script标签是不受跨域限制的,若是一个网站的前端想要获取另外一个网站的数据,能够动态的建立script标签而且在须要请求数据的那个网站后面加上查询参数,并将查询参数设置为?callback=fn的形式,后端返回函数调用的形式并将数据传进去,形如fn.call(undefined,'须要传入的数据'),因为是动态的建立script标签,那么就会执行该标签里面所传入的函数调用。只要事先写好这个函数fn的具体逻辑,那么请求方就能够获得所须要的数据了。css
总的能够概括成下面的形式:html
请求方: 例如http://127.0.0.1:8001(浏览器)前端
响应方: 例如http://127.0.0.1:8002(服务器)java
1.请求方动态建立script标签,将src指向响应方,再传入一个查询参数例如?callback=fnajax
2.响应方根据请求方传过来的查询参数的值,构造形如fn.call(undefined,'请求方想要的数据')的形式返回给请求方。(注:数据能够既能够是json格式的还能够是字符串的形式或者是html、xml等格式)json
3.浏览器接收到响应,就会执行fn.call(undefined,'请求方想要的数据')后端
4.那么请求方就能够获取到他想要的数据。跨域
以上就是所谓的jsonp。浏览器
如下是一个简单的小例子:
1.index.html代码以下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>jsonp</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<h3>您的帐户余额为<span id="amount">&&&amount&&&</span></h3>
<button id="btn">付款</button>
<script>
btn.addEventListener('click', function (e) {
// amount.innerText = parseInt(amount.innerText) - 1
let script = document.createElement('script')
let functionName = 'fn'
window[functionName] = function (result) {
if (result === 'success') {
amount.innerText = amount.innerText - 1
}
}
script.src = `http://127.0.0.1:8002/pay?callback=${functionName}`
document.body.appendChild(script)
script.onload = function (event) {
alert('success')
event.currentTarget.remove() //用完以后移除script标签和window[functionName]函数
delete window[functionName]
}
script.onerror = function () {
alert('failed')
event.currentTarget.remove()
delete window[functionName]
}
})
</script>
</body>
</html>
2.后端代码以下:
var http = require('http')
var fs = require('fs')
var url = require('url')
var port = process.argv[2]
var port = process.env.PORT || 8888
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
if (path === '/') {
response.statusCode = 200
let string = fs.readFileSync('./index.html', 'utf-8')
let money = fs.readFileSync('./data.txt', 'utf-8')
string = string.replace('&&&amount&&&', money)
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
} else if (path === '/style.css') {
response.statusCode = 200
let string = fs.readFileSync('./style.css', 'utf-8')
response.setHeader('Content-Type', 'text/css;charset=utf-8')
response.write(string)
response.end()
} else if (path === '/main.js') {
response.statusCode = 200
let string = fs.readFileSync('./main.js', 'utf-8')
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.write(string)
response.end()
} else if (path === '/pay') {
response.statusCode = 200
//先读取文件里面的金额,再将它传给前端
let money = fs.readFileSync('./data.txt', 'utf-8')
let newMoney = parseInt(money) - 1
fs.writeFileSync('./data.txt', newMoney)
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.write(`
// alert("success")
// amount.innerText = amount.innerText - 1
${query.callback}.call(undefined,'success')
`)
response.end()
} else {
response.statusCode = 404
response.write('path is wrong')
response.end()
}
})
server.listen(port)
console.log('监听 ' + port + ' 成功\n请打开 http://localhost:' + port)
复制代码
jsonp优缺点