JavaScript 【JSONP】

239 阅读4分钟

1. 数据库:只要能长久地存储数据

    。 文件系统是一种数据库
    。 MySQL是另一种(做数据库的软件)数据库

2. JSONP

访问页面中的script不受域名限制,即任何一个网站都可以使用另外一个网站的js JSONP解决的问题是两个网站之间的交流:用script标签就能交流,因为script标签是不受域名限制的,请求另一个网站的script; 异步:通过script发起请求一个网站,并声明这个网站把数据保存到一个未定名函数里面指定参数里面传出来,则请求成功后这个网站会把数据通过响应,在参数里面存储出局显示出来。以上过程用JSON语言(用双引号的js)+ 左右padding来完成的,简称JSONP,若含有参数的语句不是返回对象,而是返回一个字符串的话,模仿JSONP称为StrigP(自创,别当真); JSONP:本质上是用DOM标签动态跨域请求的过程,简单来说就是script + callback组成了JSONP;

    后端程序:
    responce.write(`
        //返回一个对象
      ${query.callbackName}.call(undefined,{//这一行是JSON 的左padding
          "success":true;
          "left":${newAmount}
          //花括号里的这两行叫做JSON
      })  //这一行是JSON 的右padding
    `)

JSONP的完整过程:

  1. 请求方:一个网站的前端(浏览器): 创建一个script,src指向响应方,同时传一个查询参数?callback=xxx;不用callbackName,而是用callback。
  2. 响应方:另一个网站的后端(服务器) 根据查询参数callbackName,构造形如xxx.call(undefined,'你要的参数')响应。
  3. 浏览器接收到响应就会执行回调函数xxx.call(undefined,'你要的参数')。
  4. 请求方就会知道了他想要的数据(执行函数体里面的执行语句)。

JSONP的行业约定:

  1. 查询参数要用callback来指定,在jQuery中用jQuery_callback。
  2. 回调函数名不固定,就用用随机函数名,简单又避免函数名重复的问题,例如不叫xxx ,而是jQuery12343这种随机数;只要符合变量名规则就行。
  3. 调用函数后马上删除,避免污染全局变量。

原生js实现JSONP的代码如下:

//前端代码
<title>浏览器代码</title>
<link rel="stylesheet" href="./style.css">
<!---用占位符表示动态数据--->
<h5>您的账账户余额是 <span id="amount">&&&amount&&&</span></h5>
<button id="button">打钱</button>
<script>
    //不能用get请求,别人很容易伪造,必须用post请求
    button.addEventListener('click', (e) => {
        //用动态script创建一个GET请求法
        let script = document.createElement('script')
        //得到一个形如frank24325435的函数名
        let functionName = 'frank' + parseInt(Math.reandom() * 100000,10) //Math.random是小数,乘一个100000后得到一个0-10万的小数,再取整
        window[functionName] = function (result) {
            if (result === 'success') {
                amount.innerText = amount.innerText - 1
            } else {

            }
        }
        //script的source就是请求的路径
        script.src = 'http://jack.com:8082/pay?callback' + functionName
        //script创建请求必须放在页面中,这样浏览器就会发起一个get请i去(没有办法创建post请求)
        document.body.appendChild(script)
        script.onload = function (e) {
            //不管有没有成功都要删掉script
            e.currentTarget.remove()
            //不管成功与否都要把这个函数删除掉
            delete window[functionName]
        }
        script.onerror = function (e) {
            alert('fail')
            e.currentTarget.remove()
            delete window[functionName]
        }


        //用动态img创建一个get请求法
        //let image = document.createElement('img')
        //image.src = '/pay'
        //image.onload = function(){ 
        //alert('打钱成功')
        //amount.innerText = amount.innerText - 1
        //}
        //image.onerror = function(){
        //alert('打钱失败')
        //}
    })
</script>
    JSONP用jQuery实现
    <title>首页</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<link rel="stylesheet" href="./style.css">
<!---用占位符表示动态数据--->
<h5>您的账账户余额是 <span id="amount">&&&amount&&&</span></h5>
<button id="button">打钱</button>


<script>
    button.addEventListener('click', function () {
        // Using YQL and JSONP
        //虽然名字是ajax,但是和AJAX没有任何关系
        $.ajax({
            url: "http://jack.com:8082/pay",
            // Tell jQuery we're expecting JSONP
            dataType: "jsonp",
            // Work with the response
            success: function (response) {
                // server response
                if (response === 'success') {
                    amount.innerText = amount.innerText - 1
                } else {

                }
            }
        });
    })
</script>
    //服务器端代码
    var http = require('http')
    var fs = require('fs')
    var url = require('url')
    var port = process.argv[2]

    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 path = request.url
        var query = ''
        if (path.indexOf('?') >= 0) {
            query = path.substring(path.indexOf('?'))
        }
        var pathNoQuery = parsedUrl.pathname
        var queryObject = parsedUrl.query
        var method = request.method

    /*******  从这里开始看,上面不要看 *******/
    /****服务器返回的javascript方法 SRJ(server rendered javascript )*****/
    if (path === '/') { //如果用户请求的是 / 路径
        var string = fs.readFileSync('./index.html', 'utf8')
        //通过读db.xxxx文件
        var amount = fs.readFileSync('./db', 'utf8') //db的值为100,类型为string
        //把db.xxxx文件中的数据放进来
        string = string.replace('&&&amount&&&', amount)
        response.setHeader('Content-Type', 'text/html;charset=utf-8')
        response.write(string)
        response.end()
    } else if (path === '/style.css') {
        var string = fs.readFileSync('./style.css', 'utf8')
        response.setHeader('Content-Type', 'text/css')
        response.write(string)
        response.end()
    } else if (path === '/main.js') {
        var string = fs.readFileSync('./main.js', 'utf8')
        response.setHeader('Content-Type', 'application/javascript')
        response.write(string)
        response.end()
    } else if (path === '/pay') {
        //如果浏览器发起的请求成功了,服务器返回javascript响应
        var amount = fs.readFileSync('./db', 'utf8') //db的值为100,类型为string
        var newAmount = amount - 1
        fs.writeFileSync('./db', newAmount)
        response.setHeader('Content-Type', 'application/javascript')
        response.statusCode = 200
        //响应内容就是操作页面局部刷新,括号里的代码会被当作js执行是基于http协议
        response.write(`
        ${jQuery.callback}.call(undefined,'success')
        `)
        response.end()
    } else {
        response.statusCode = 404
        response.setHeader('Content-Type', 'text/html;charset=utf-8')
        response.write('找不到对应的路径,你需要自行修改路径 index.js')
        response.end()
    }


    /******* 代码结束,下面不要看*******/
        console.log(method + ' ' + request.url)
    })


    server.listen(port)
    console.log('监听 ' + port + ' 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:' + port)

JSONP【面试题目】:

  1. JSONP为什么不支持POST请求? 因为JSONP是通过动态创建scriipt实现的,动态创建的script的时候只能发送get请求,不能发送post请求.

  2. 什么是JSONP?

    1. 请求方:frank.com 的前端程序员(浏览器)

    2. 响应方:jack.com 的后端程序员(服务器)

        i. 请求方创建 script,src 指向响应方,同时传一个查询参数 ?callbackName=yyy
        ii. 响应方根据查询参数callbackName,构造形如
         yyy.call(undefined, '你要的数据')
         yyy('你要的数据')
         这样的响应
      

    3.浏览器接收到响应,就会执行 yyy.call(undefined, '你要的数据')

    4.那么请求方就知道了他要的数据

    这就是 JSONP

    约定:

     callbackName -> callback
     yyy -> 随机数 frank12312312312321325()
    

    jQuery 用法

             $.ajax({
                url: "http://jack.com:8002/pay",
                dataType: "jsonp",
                success: function( response ) {
                    if(response === 'success'){
                 amount.innerText = amount.innerText - 1
                     }
                }
            })