JSONP

JSONP是什麼?

JSONP的歷史, 就是前端程序員爲了優化用戶體驗而造成的javascript

首先來看一下瀏覽器看見什麼會立刻進行請求?html

  1. form
  2. a
  3. link
  4. image
  5. script

前三個就不說了,很簡單~, 重點說下imagescript前端

image發送請求

服務器端代碼:java

response.setHeader('Content-Type', 'image/jpeg')
response.statusCode = 200
response.write(fs.readFileSync('./dog.jpeg'))
// 必須寫入一個真實的圖片,請求才會成功
複製代碼

前端代碼:node

let image = document.createElement('img')
image.src = '/pay'
image.onload = function(){
	alert('打錢成功')
	window.location.reload() // 刷新頁面
}
image.onerror = function(){
	alert('打錢失敗')
}
// 利用圖片的加載成功和失敗,來判斷請求是否成功.
複製代碼

script發送請求

script元素能夠做爲一種Ajax傳輸機制:只須設置script元素的src屬性(假如它還沒插入到document中,須要插入進去),而後瀏覽器就會發送HTTP請求下載src屬性程序員

所指向的URL。使用script元素進行Ajax傳輸的一個主要緣由是,它不受同源策略的影響(不受域名限制),所以能夠使用它們從其餘的服務器請求數據,第二個緣由是包含JSON編碼數據的響應體會解碼。 這種使用script元素做爲Ajax傳輸的技術稱爲JSONPjson

說道script就和JSONP有關了後端

什麼是JSONP?跨域

全稱 JSON with Padding,用於解決AJAX跨域問題的一種方案。瀏覽器

因爲同源策略的限制,瀏覽器只容許XmlHttpRequest請求當前源(域名、協議、端口)的資源,而對請求script資源沒有限制。經過請求script標籤實現跨域請求,而後在服務端輸出JSON數據並執行回調函數,這種跨域的數據的方式被稱爲JSONP。

JSONP是一種非正式傳輸協議,該協議的一個要點就是容許用戶傳遞一個callback參數給服務端,而後服務端返回數據時會將這個callback參數做爲函數名來包裹住JSON數據,這樣客戶端就能夠隨意定製本身的函數來自動處理返回數據了。

具體步驟爲:

請求方: xxx.com 的前端程序員(瀏覽器)

響應方: yyy.com 的後端程序員(服務器)

  1. 請求方建立 script, src指向響應方, 同時傳遞一個查詢參數 ?callback=xxx

  2. 響應方根據查詢參數 callback, 構造形如

    1. xxx.call(undefined, '你要的數據')
    2. xxx('你要的數據')

    這樣的響應

  3. 瀏覽器接受到響應, 就會執行 xxx.call(undefined, '你要的數據')

  4. 那麼請求方就知道了他要的數據

JSONP的行業要求

  1. callback
  2. 上面的xxx換成xxx+隨機數(), 例如xxx23231321, 防止污染全局變量

JSONP代碼

服務器代碼: 域名爲jack.com:8002

var http = require('http')
var fs = require('fs')
var url = require('url')
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 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 === '/') { // 當請求路徑爲 '/' 時, 返回一個index.html
        var string = fs.readFileSync('./index.html', 'utf8')
        var amount = fs.readFileSync('./db', 'utf8')
        string = string.replace('&&&amount&&&', amount)
        response.setHeader('Content-Type', 'text/html;charset=utf-8')
        response.end(string)
    } else if (path === '/pay') { // 當請求路徑問 '/pay'時
        var amount = fs.readFileSync('./db', 'utf8')
        var newAmount = amount - 1
        fs.writeFileSync('./db', newAmouznt)
        response.setHeader('Content-Type', 'application/javascript')
        response.statusCode = 200
        response.write(` ${query.callback}.call(undefined,'success') `)
        response.end()
    } else {
        response.statusCode = 404
        response.setHeader('Content-Type', 'text/html;charset=utf-8')
        response.end()
    }
})
server.listen(port)
複製代碼

上面的代碼

response.write(${query.callback}.call(undefined,'success'))

第二個參數爲string, 也能夠叫作StringP, 若是換成JSON,就是JSONP.

${query.callbackName}.call(undefined,{
	"success": true,
	"left": ${newAmount}
})
// JSON: { "success": true,"left": ${newAmount}}
// 左padding: ${query.callbackName}.call(undefined,
// 右padding: )
複製代碼

前端代碼: 域名爲frank.com:8001

<h5>您的帳戶餘額是 <span id='amount'>&&&amount&&&</span></h5>
    <button id="button">付款</button>
    <script> button.addEventListener('click', function (e) { let script = document.createElement('script') let functionName = 'frank' + parseInt(Math.random() * 100000, 10) // 前端聲明一個函數, 給後端調用, 函數名經過callback傳遞給後端 window[functionName] = function (result) { // 後端返回result, 能夠是json, 能夠是string if (result === 'success') { alert(`我獲得的結果是${result}`) amount.innerText = amount.innerText - 1 } else { alert('fail') } } script.src = 'http://jack.com:8001/pay?callback=' + functionName document.body.appendChild(script) script.onload = function (e) { e.currentTarget.remove() // 移除script delete window[functionName] } script.onerror = function () { alert('打錢失敗') e.currentTarget.remove() delete window[functionName] } }) </script>
複製代碼

問題: JSONP爲何不支持 POST 請求?

由於JSONP是經過動態建立script來實現的, 動態建立的script只能用GET,不能用POST.

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息