美文网首页
前端向后端发送请求,JSONP学习笔记

前端向后端发送请求,JSONP学习笔记

作者: Criya | 来源:发表于2018-05-19 14:35 被阅读0次

原始时代

在最早的时候,当我们需要向服务器提交请求时,用的是<form>表单提交到服务器,服务器接收到请求并且返回响应后,浏览器的页面是会刷新的。也就是说我们每次更新一个数据,都需要刷新当前页面一次,这种行为是无法忍受的。

为了解决这个问题,前辈们最先想到的方法就是使用一个<iframe>,将刷新结果放在<iframe>中显示,这样我们页面浏览就不会受到太大的影响。

    <form action="/pay" method="POST" target="result">
        <input type="submit" value="付款">
    </form>
    <iframe src="about:blank" frameborder="0" height="200px" name="result"></iframe>

<iframe>的各种缺点就不提了,随着技术的发展与进步现在几乎没有多少网页会再使用<iframe>了。

于是乎为了避免使用<iframe>,前辈们又思考是否可以不用<form>发送请求呢?
我们发现<img> <link> <a>,这些标签都是通过向服务器发送请求以获取资源的,也就是说我们可以用这些标签代替<form>向服务器发送一个请求。

用img构建GET请求

img的加载就是一个GET请求,如果我们用img来加载一个假的图片的话,就可以变相伪造一个请求了。

    <button id="button">付款</button>
    <script>
        button.onclick = ()=> {
            let img = document.createElement("img");
            img.src = "/pay"
            img.onload = ()=> {
                alert("付款成功")
            }
            img.onerror = () => {
                alert("付款失败")
            }
        }
    </script>

这样我们就可以通过动态创建一个img设置它的src为服务器请求地址,来构造一个GET请求(使用这种方法无法产生POST请求)。这样后端再做一些处理(例如当成功时返回一个1x1的透明图片),前端就可以通过onload和oneror来判断请求成功与否。

用script构建GET请求

<img>一样,<script>也可以通过src来访问服务器。

    <button id="button">付款</button>
    <script>
        button.onclick = ()=> {
            let spt = document.createElement("script");
            spt.src = "/pay";
            document.body.appendChild(spt);

            spt.onload = ()=> {
                alert("付款成功");
            }
            spt.onerror = () => {
                alert("付款失败");
            }
        }
    </script>

<img>不同的是,动态创建的<script>必须插入到html中才能生效。
与上面一种方法相比较,动态创建js的方式不需要添加一个无谓的图片来浪费,但是js也是有自己的副作用的,那就是服务器返回的js代码一定会执行(因为它已经添加的html中了),由此我们可以延伸出直接通过后端来响应页面的成功请求。
我们前端就不需要像之前那样监听onload事件了,因为后端返回的<script>会先执行,我们在那上面执行成功代码就可以了。
因为每次响应都会在html添加一个<script>非常不美观,所以我们在onload里把至这些新插入的标签移除就可以了。

button.onload = (e)=>{
    e.currentTarget.remove();
}

这种方案通过动态创建<script>来构造GET请求的方法被叫做SRJ, server render javascript。

JSONP跨站请求

我们发现,使用html的带有src属性的标签都可以构造一个GET请求(不能构造POST),并且这个请求是可以跨站的。
于是,基于SRJ便诞生出了利用<script>来构建跨站请求的方法JSONP:JSON with PADDING
虽然名字里带了JSON但这个JSONP和JSON没有半毛钱关系,不要误会了,JSONP是一种跨站请求方案的名字。

那么什么是JSONP呢?

我们前端发送跨站请求时,查询参数附上一个我们前端定好的函数。

    <script>
        var fuckBrowser = (response)=>{
            if (response === 'sucess'){
                console.log("scuess");
            }
        }
        var script = document.createElement("script");
        script.src = 'http://www.domain.com/?callbackName=fuckBrowser'
    </script>

对面的后端接收的GET请求后作出判断,若成功,则发送响应,这个响应的内容就是让我们这边的前端执行查询参数上的函数。

//后端响应
if(响应成功条件满足){
  //这里后面的callback就是url里的?callback=''
    var callbackFunctionName = request.query.callback;
  //这样后端就可以知道前端定好的函数是fuckBrowser
  // callbackFunctionName === fuckBrowser  /*true*/
  response.write('callbackFunctionName.call(undefined, 'scuess')');
  //这样前端就会执行fuckBrowser并且第二个参数时scuess
}

这就是一个简单JSONP例子,这样就可以达到前后端分离的跨站请求,不过我们还是要遵循一些业界的规定。

  1. 这个回调函数的参数名统一命名为callback
  2. callback的函数名为随机数

上面的后端如果返回的不是’scuess’而是一个json对象,那么这就符合最初JSONP设计的初衷了,不过现在的JSONP更多指的是这样一种跨站请求解决方法的形式。

JSONP总结

JSONP的全称是 json with padding,它是利用SRJ(服务器响应创建js)技术来达成发送跨站请求。

  1. 前端首先定义好一个用来接收后端数据的functionName(参数1, 参数2)
  2. 前端在发送查询请求的URL中指定一个callback参数?callback=fuctionName,并且这个functionName应该是由随机数组成(防止重名与缓存)
  3. 后端通过request解析callback的名字(后端并不需要知道它叫什么)
  4. 后端返回一个response,这个response是要求前端执行在1中前端定义好的functionName也就是传进来的callback
  5. 4中执行的callback的参数是由后端的数据提供的,可以是字符串也可以是JSON

这个流程就是JSONP,解决跨站请求的方案

相关文章

网友评论

      本文标题:前端向后端发送请求,JSONP学习笔记

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