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那样获取精确的状态码,只知道成功或者失败。
相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息