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

原始时代

在最早的时候,当我们需要向服务器提交请求时,用的是<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,解决跨站请求的方案

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容