美文网首页我爱编程小志的前端之路
用代码理解--JSONP到底是什么鬼

用代码理解--JSONP到底是什么鬼

作者: 小志1 | 来源:发表于2018-04-03 00:00 被阅读0次

    html实现打钱效果

    <h5>您的账户余额是 <span id="number">100</span></h5>
    <button id="button">付款</button>
    button.addEventListener("click", function(){
      number.innerText = number.innerText - 1
    })
    

    接下来用node来实现后台打钱效果
    创建index.js文件,下面代码第二部分写在里面,并且通过命令行node index 8888打开。

    <form action="/pay" method="post">
      <input type="submit" value="付款">  
    </form>
    
    //index.js
    if(path === '/pay' && method.toUpperCase() === 'POST'){
        var amount = fs.readFileSync('./db', 'utf8')
        var newAount = amount - 1
        if(Math.random() > 0.5){
          fs.writeFileSync('./db', newAount)
          response.statusCode = 200
          response.write("success")   
        } else{
          response.statusCode = 400
          response.write("fail")
        }
        response.end()  
      }
    

    但是用form表单一旦提交了就一定会刷新当前页面。 这里用iframe,是了解前端的历史。

    下面用image图片提交

    
    button.addEventListener("click", function(e){
            let img = document.createElement("img")
            img.src = "/pay"
            img.onload = function(){
                alert("打钱成功")
            }
            img.onerror = function(){
                alert("打钱成功")
            }
        })
    
    对应的index.js里的类型要修改成图片格式
    //index.js
    if(path === '/pay' ){
      var amount = fs.readFileSync('./db', 'utf-8')
      var newAmount = amount - 1
      if(Math.random()>0.5){
        fs.writeFileSync('./db',newAmount)
        response.setHeader('Content-Type', 'img/jpg')
        response.statusCode = 200
        response.write(fs.readFileSync('./dog.jpg'))
      }else{
        response.statusCode = 400
        response.write('fail')
      }
        response.end()
    }
    

    用图片发请求挺厉害的,但是还有更厉害的:用script发请求。
    script发请求,再建一个叫db的文件,后缀无所谓,在文件里写个数据 '100' (相当于数据库)

    <h5>账户余额是<span id="amount">&&&amount&&&</span></h5>
    
    buttonss.addEventListener('click',(e)=>{
        let script = document.createElement('script')
        script.src = '/pay'
        script.onload = function(e){
          e.currentTarget.remove()
        }
        document.body.appendChild(script)
        script.onerror = function(e){
          alert('fail')
          e.currentTarget.remove()
        }
    })
    
    //index.js
    if(path === '/pay' ){
      var amount = fs.readFileSync('./db', 'utf-8')
      var newAmount = amount - 1
      fs.writeFileSync('./db',newAmount)
      response.setHeader('Content-Type', 'application/javascript')
      response.statusCode = 200
      response.write(`
        amount.innerText = amount.innerText - 1
      `)
      response.end()
    }
    

    这个方案叫做SRJ Server rendered javascript, 服务器返回的JavaScript 。

    访问另一个网站的script

    用命令行添加两个hosts sudo vi /etc/hosts(要权限),也可以打开这个文件添加两个hosts

    添加hosts
    然后开两个server 设置端口可以用:PORT=8001 node index.jsPORT=8002 node index.js
    开两个端口
    端口1
    端口2
    下面我想让frank.com的前端去访问jack.com的后端。
    在index.html里面的一句改成script.src = 'http://jack.com:8002/pay'
    然后点击frank.com的打钱,就访问了jack.com的钱。

    接下来的jsonp,上面的代码中,在index.js里面。

    response.write(`
        amount.innerText = amount.innerText - 1
      `)
    

    这代码的要求是jack.com的后端需要对frank.com的前端页面细节了解,存在耦合。关系太紧密了,要解耦。
    在index.js改成

    response.write(`
            xxx.call(undefined,'success)
        `)
    

    然后在html里写好

    window.xxx = function(result){
        alert('这是frank写的前端代码')
        alert(`我得到的结果是${result}`)
     }
    

    这样点击按钮的时候script.src = 'http://jack.com:8002/pay'就index.js不需要知道任何信息,调用xxx就行了,然后把结果(success或者fail)告诉前端,前端通过success或者fail告诉用户失败还是成功了。

    代码优化和完全解耦

    //html
    script.src = 'http://jack.com:8002/pay?callbackName=xxx'
    
    //index.js
    response.write(`
          ${query.callbackName}.call(undefined,'success')
        `)
    

    这样index.js(后台)就不用关心细节了,给什么就调什么,这样就完全耦合了,这就是jsonp。

    response.write(`
          ${query.callbackName}.call(undefined,{
            "success": true,
            "left": ${newAmount}
          })
        `)
    

    undefined后面的花括号是json,后面有个尾')',前面有代码,叫做左padding和右padding,所以 json+padding = jsonp。jsonp就是这么来的。但是json有时候不是json,因为一般用string比较多。
    jsonp可以理解为动态标签跨域请求。

    buttonss.addEventListener('click',(e)=>{
        let script = document.createElement('script')
        let functionName = 'frank' + parseInt(Math.random()*100000,10)
        window[functionName] = function(result){
          if(result === 'success'){
            amount.innerText = amount.innerText - 1
          }else{
    
          }
        }
        script.src = 'http://jack.com:8002/pay?callback=' + functionName
        document.body.appendChild(script)  //img不需要这个,但是script需要
        script.onload = function(e){
          e.currentTarget.remove()
          delete window[functionName]
        }
        script.onerror = function(e){
          alert('fail')
          e.currentTarget.remove()
          delete window[functionName]
        }
      })
    

    可以用jQuery简写

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

    这个方法ajax一点关系都没有,它是个动态script

    代码:https://github.com/xiaozhi1/nodejs-test
    为什么JSONP 为什么不支持 POST
    • 因为jsonp是通过动态创建script实现的
    • 动态创建script的时候只能用get,没有办法用post
    JSONP

    请求方:frank.com 的前端程序员(浏览器)
    响应方:jack.com 的后端程序员(服务器)

    • 请求方创建 script,src 指向响应方,同时传一个查询参数 ?callbackName=xxx
    • 响应方根据查询参数callbackName,构造形如
      1.xxx.call(undefined, '你要的数据')
      2.xxx('你要的数据')
      这样的响应
    • 浏览器接收到响应,就会执行 xxx.call(undefined, '你要的数据')
    • 那么请求方就知道了他要的数据
      这就是 JSONP
    约定:
    • callbackName -> callback
    • xxx -> 随机数 frank12312312312321325()

    相关文章

      网友评论

        本文标题:用代码理解--JSONP到底是什么鬼

        本文链接:https://www.haomeiwen.com/subject/leffhftx.html