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優缺點