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

html实现打钱效果

您的账户余额是 100
button.addEventListener("click", function(){ number.innerText = number.innerText - 1 })

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

//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' (相当于数据库)

账户余额是&&&amount&&&
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

用代码理解--JSONP到底是什么鬼_第1张图片
添加hosts

然后开两个server 设置端口可以用: PORT=8001 node index.jsPORT=8002 node index.js
开两个端口

用代码理解--JSONP到底是什么鬼_第2张图片
端口1

用代码理解--JSONP到底是什么鬼_第3张图片
端口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到底是什么鬼)