JSONP入门

作者: zzzZink | 来源:发表于2018-05-15 21:45 被阅读0次

啥是JSONP?

首先引入一个需求:


需求

用户每点击一下付款按钮,页面和数据库中的余额减少1。
先来理解一下客户端和服务器的交互过程:

  • 客户端发起请求
  • 服务器接受请求并处理
  • 服务器返回数据到客户端

但是,HTML标签中能发请求的标签很少,比如<a>标签、<form>标签、<link>标签、<script>标签、<img>标签等。


方案一:使用表单<form>发请求
HTML

<body>
    <h5>你的账户余额为<span id="amount">&&&amount&&&</span></h5>
    <form action="/pay" method="post">
        <input type="submit" value="付款1块钱">
    </form>
</body>

向服务器发起请求,请求结果返回到pay页面。
form表单一旦提交就会刷新页面,进入pay页面,需要用户退回index页面,刷新页面才能看到结果。


方案二:使用表iframe
HTML

<body>
    <h5>你的账户余额为<span id="amount">&&&amount&&&</span></h5>
    <form action="/pay" method="post" target="result">
        <input type="submit" value="付款1块钱">
    </form>
    <iframe src="about:blank" frameborder="0" name="result" height="200"></iframe>
</body>
点击付款前 点击付款后,付款成功 刷新页面余额改变

以上两种方法是以前的使用方法。


方案三:动态创建图片发请求:
HTML:

<body>
    <h5>你的账户余额为<span id="amount">&&&amount&&&</span></h5>
    <button id="button">付款1块钱</button>
    <script>
        button.addEventListener('click', (e) =>{
            let image = document.createElement('img')
            image.src = '/pay'
        })
    </script>
</body>
点击按钮后请求成功

但是这样用户并不知道请求到底是否成功。因为页面并没有刷新产生任何变化。
修改代码为:

<script>
        button.addEventListener('click', (e) =>{
            let image = document.createElement('img')
            image.src = '/pay'
            image.onload = function () {
                alert('打钱成功')
                window.location.reload() //刷新页面
            }
            image.onerror = function () {
                alert('打钱失败')
            }
        })
    </script>

虽然成功请求到了,但是为社么么会显示打钱失败?
因为后端代码中返回的不是真图片只是图片格式,被浏览器识别出来,导致image.onerror执行,如果使用的是真图片就会执行image.onload

使用image发请求有一个弊端,只能发起GET请求不是发起POST请求。


方案四:使用script发起请求(JSONP)

<body>
    <h5>你的账户余额为<span id="amount">&&&amount&&&</span></h5>
    <button id="button">付款1块钱</button>
    <script>
        button.addEventListener('click', (e) =>{
            let script = document.createElement('script')
            script.src = '/pay'
            document.body.appendChild(script)
            script.onload = function(){
                alert('success')
                window.location.reload() //刷新页面
            }
            script.onerror = function(){
                alert('fail')
            }
        })
    </script>
</body>

使用image不用放入页面就能发起请求,script必须要放入页面才能发起请求

请求成功

但是这种方法会在页面中放入一个script,并且里面的内容会执行,所以我们可以不用监听script.onload,直接在后端返回的script中写入我们要执行的代码。
node.js:

 response.write(`alert('success')
                 window.location.reload()`)

但是页面最后会插入script标签,于是请求成功之后删除script(SRJ方案)

script.onload = function(e){
  e.currentTarget.remove()
}

但依然存在于内存,只是在页面中消失
JavaScript可以跨域请求。可以在xxx.com的网站中请求zzz.com的JS,但是script请求也是GET,这样容易被伪造,重要操作使用POST请求。


JSONP解决了两个网站跨域交流的问题
原生JS

button.addEventListener('click',(e)=>{
  let script = document.createElement('script');
  let functionName = 'zink'+parseInt(Math.random()*100000,10);
  window[functionName] = function (result) {
    if(result === 'success'){
      amount.innerText = amount.innerText - 1
    }else {
      alert(`fail`)
    }
  };

  script.src = 'http://jack.com:8002/pay?callback=' + functionName;
  document.body.appendChild(script);
  script.onload = function (e) {
    e.currentTarget.remove();
    delete window[functionName]
  };
  script.onerror = function (e) {
    alert('fail');
    e.currentTarget.remove();
    delete window[functionName]
  }
});

跨域请求
请求方:zink.com的前端程序员(浏览器)
响应方:jack.com的后端程序员(服务器)
1.请求方创建script,src指向响应方,同时传一个查询参数 ?callbackName=xxx

response.write(`
  ${query.callback}.call(undefined,'success')
`)

JSONP示例:
response.write(`
  ${query.callback}.call(undefined,{    //左padding
    "success": true,                    //这一部分是JSON
    "left": ${newAmount} }              //这一部分是JSON
    )                                   //右padding
`)                                      //右padding
//JSON + padding = JSONP

这句话是精髓
${query.callback}.call(undefined,'success')
'success'是JSON,左边的叫左padding,右边的括号叫右padding,合起来叫JSONP
这样来调用请求方的callback函数,名字是functionName。

这里才是正经方法
2.服务器通过响应方根据查询参数callbackName,构造形如以下的响应

  • functionName.call(undefined, '你要的数据')
  • functionName('你要的数据')

3.浏览器接收到响应,就会执行functionName.call(undefined, '你要的数据')
4.那么请求方就知道了他要的数据
这就是JSONP

约定:

  • callbackNmae —> callback
  • functionName 是一个随机数

jQuery写法:
注意是JSONP不是ajax

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

面试题:请问JSONP为什么不支持POST请求?
因为JSONP的本质是动态创建script发起请求,而js动态创建cript只能发起GET请求,所以无法支持POST请求。

相关文章

  • JSONP入门

    啥是JSONP? 首先引入一个需求: 用户每点击一下付款按钮,页面和数据库中的余额减少1。先来理解一下客户端和服务...

  • jsonp——简单跨域解决方法

    作为入门级菜鸟,之前一直以为jsonp只是json多个p的别名,惭愧惭愧。jsonp只是json的一种使用模式,是...

  • JSONP、JQuery发送AJAX、JSONP请求

    1.JSONP 2.JQuery发送AJAX、JSONP请求 1.JSONP JSONP利用JavaScript...

  • JS-18day

    1、jsonp公开接口 2、jQuery-jsonp 3、jsonp

  • 2018-12-10

    节点操作 ajax jsonp jQuery-jsonp jsonp公开接口

  • jsonp原理

    模拟jsonp原理 servlet 测试 http://localhost/jq/jsonp.jsp JSONP ...

  • 2018-07-30

    一 ajax 二 jsonp 三 jquery-jsonp 四 jsonp公开接口

  • ajax

    1、ajax 2、jsonp 3、jQuery-jsonp 4、jsonp公开接口

  • javasscript - 收藏集 - 掘金

    jsonp 跨域请求详解——从繁至简 - 前端 - 掘金什么是jsonp?为什么要用jsonp?JSONP(JSO...

  • 33-高级:JSONP入门

    请先了解:《阮一峰:浏览器同源政策及其规避方法》 注意:请首先更新之前用过的 nodejs-test 代码,否则会...

网友评论

    本文标题:JSONP入门

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