JSONP
是什麼Jsonp
(JSON with Padding
) 是 json
的一種"使用模式",可讓網頁從別的域名(網站)那獲取資料,即跨域讀取數據。javascript
<h5>您的帳戶餘額是<span id="amount">&&&amount&&&</span></h5>
<button id="button">付款</button>
複製代碼
form
發請求<form action="/pay" method="POST" target="result">
<input type="submit" value="付款">
</form>
<iframe name="result" src="about:black" frameborder="0" height="200"></iframe>
複製代碼
後端部分代碼:html
if(path === '/'){
let string=fs.readFileSync('./index.html','utf8')
let amount=fs.readFileSync('./db','utf8')
string=string.replace('&&&amount&&&',amount)
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(string)
response.end()
}else if (path === '/pay') {
let amount = fs.readFileSync('./db', 'utf8')
let number = amount - 1
if(Math.random() > 0.5){ //假設大於0.5就成功
fs.writeFile('./db', number)
response.write('success')
}else{
response.write('fail')
}
response.end()
}
複製代碼
form
表單提交以後必定會刷新當前頁面,這樣用戶體驗很差,利用 iframe
局部刷新頁面,優化用戶體驗。前端
有沒有想過,不返回 HTML
,返回 JS
java
get
請求瀏覽器有個特色一旦發現你在內存裏建立了一個 img
,就會去請求這個 img
,這個方法能夠悄無聲息的創造一個請求,但有個缺陷沒法設置 POST
。那就 發GET
請求吧,總比用 iframe
刷新頁面好。程序員
button.addEventListener('click', () => {
let image = document.createElement('img')
image.src = './pay'
image.onload = function(){
alert('付款成功')
amount.innerText = amount.innerText -1
}
image.onerror = function(){
alert('付款失敗')
}
})
複製代碼
瀏覽器怎麼知道一個圖片請求是成功仍是失敗呢?狀態碼說的很清楚,假設若是成功就返回 200
,失敗返回 400
ajax
if (path === '/pay') {
let amount = fs.readFileSync('./db', 'utf8')
let number = amount - 1
if(Math.random() > 0.5){
fs.writeFile('./db', number)
response.setHeader('Content-Type', 'image/png')
response.statusCode = 200
response.write(fs.readFileSync('./th.jpg'))
}else{
response.statusCode = 400
response.write('fail')
}
response.end()
}
複製代碼
這樣就作到了無刷新的也沒有用什麼特殊的技術,只用了一個小技巧就是建立了一個 img
用它發請求。如今的問題就是沒法 POST
,由於瀏覽器沒有給咱們一個接口讓咱們 POST
,因此那就只好 GET
了, 這種方法只能知道成功或失敗,不能知道更多的數據。json
script
造 get
請求這種方法必定要把 script
放到頁面裏面,瀏覽器纔會發起請求。怎麼樣才能知道是請求成功仍是失敗了呢,固然 script
也有 onload
和 onerror
事件。後端
button.addEventListener('click', () => {
let script = document.createElement('script')
script.src = '/pay'
document.body.appendChild(script)
script.onload = function(){
alert('付款成功')
amount.innerText = amount.innerText -1
}
script.onerror = function(){
alert('付款失敗')
}
}
複製代碼
改進以後的好處就是不用返回圖片了,返回一個字符串就能夠了,這樣請求就會快一點了。跨域
點擊 button
後,就會去建立一個 script
標籤會放在頁面的最後方,因爲頁面中出現了一個 script
,瀏覽器就會將 /pay
裏面的內容執行掉。這樣就不須要去監聽 onload
事件,就監聽 onerror
事件就能夠了。 onload
之間由 /pay
裏面的內容執行,服務器直接返回了在瀏覽器執行的一個 js
字符串(代碼)。瀏覽器
if (path === '/pay') {
let amount = fs.readFileSync('./db', 'utf8')
let number = amount - 1
if(Math.random() > 0.5){
fs.writeFile('./db', number)
response.setHeader('Content-Type', 'application/javascript')
response.statusCode = 200
response.write(`
alert("付款成功")
amount.innerText = amount.innerText -1
`)
}else{
response.statusCode = 400
response.write('fail')
}
response.end()
}
複製代碼
不過還有一個問題就是沒點擊一次按鈕,頁面中都會多出現一個 script
,雖說不會出現 BUG,可是會很難看,因此在請求成功或失敗以後再刪除它。
button.addEventListener('click', () => {
let script = document.createElement('script')
script.src = '/pay'
document.body.appendChild(script)
script.onload = function(e){
e.currentTarget.remove()
}
script.onerror = function(e){
alert('付款失敗')
e.currentTarget.remove()
}
})
複製代碼
這就是整個的完整方案,當用戶點擊一個動做的時候,生成一個 script
,而後 script
的 src
就是要請求的路徑。而後把 script
放到頁面裏,這樣瀏覽器就是去發起一個這樣路徑的 GET
請求(沒辦法 POST
)。若是這個請求成功了,那麼它首先會執行那個服務器返回的 javascript
響應,這個響應就是操做頁面的局部刷新。
這種技術就叫作 SRJ - Server Rendered JavaScript
,服務器返回的 JavaScript
。這個就是在 AJAX
出現以前用的無刷新局部更新頁面內容。
上面的這個 SRJ
方案,若是沒有作任何的安全措施的話,任何一個網站均可以去請求這個 API
操做付款,因此像付款這些重要的操做要使要 POST
,GET
太容易僞造了。
上面都是都一個網站的前端和後端交流,那若是這個網站的前端想和另外一個域名下的接口交流怎麼辦呢?
前端給後端一個函數,而後後端調用這個函數,要執行的代碼不要管,而後返回一個結果。那後臺怎麼知道這個函數名呢,咱們能夠在請求的時候傳參。
window.yyy = function(result) {
if(result === 'success'){
amount.innerText = amount.innerText - 1
}else{
}
}
button.addEventListener("click", () => {
let script = document.createElement("script");
script.src = 'http://jackma.com:8002/pay?callback=yyy'
document.body.appendChild(script)
script.onload = function(e) {
e.currentTarget.remove()
}
script.onerror = function(e) {
e.currentTarget.remove()
}
})
複製代碼
if (path === '/pay') {
let amount = fs.readFileSync('./db', 'utf8')
let number = amount - 1
fs.writeFile('./db', number)
response.setHeader('Content-Type', 'application/javascript')
response.statusCode = 200
response.write(`
${query.callback}.call(undefined, 'success')
`)
response.end()
}
複製代碼
給什麼就調什麼,這樣就徹底耦合了, 這就叫作 JSONP
。 JSONP
要結決的一個問題就是兩個網站之間怎麼交流,咱們用一個 script
標籤就能夠交流了, script
標籤是不受域名限制的。既然不受限制,就能夠告訴對方網站我要請求一個數據,對方給數據以後再調用咱們準備的函數,把參數傳到函數的第一個參數裏面,咱們就能夠獲得了。
請求方:frank.com
的前端程序員(瀏覽器)
響應方:jack.com
的後端程序員(服務器)
請求方建立 script
,src
指向響應方,同時傳一個查詢參數 ?callback=yyy
yyy
通常是要隨機數,這樣就不用出現函數名重複的問題。
響應方根據查詢參數 callback
,構造形如
yyy.call(undefined, '你要的數據')
yyy('你要的數據')
這樣的響應瀏覽器接收到響應,就會執行 yyy.call(undefined, '你要的數據')
那麼請求方就知道了他要的數據
這就是 JSONP
jQuery
的寫法:
$.ajax({
url: "http://jack.com:8002/pay",
dataType: "jsonp",
success: function( response ) {
if(response === 'success'){
amount.innerText = amount.innerText - 1
}
}
})
複製代碼
JSONP
爲何不支持 POST
請求
由於
JSONP
是經過動態建立script
實現的,動態建立script
的時候只能用GET
請求,沒有辦法用POST
請求。