JSONP

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

  1. 兼容IE六、七、八、9,能夠進行跨域訪問。
  2. 因爲是動態生成的script標籤,只能是get請求,不支持post。
  3. 因爲是動態生成的script標籤,沒法向ajax那樣獲取精確的狀態碼,只知道成功或者失敗。
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息