就算你懂了JSONP,那你又懂AJAX吗?

    上篇文章我们说到了什么是JSONP以及JSONP的用法,但说到底,JSONP终究只是一种以脚本的形式来运行的方法,并且,它只能向服务器发送GET请求,原则上不能发送其他如POST、PUT的请求的。因此在这里向大家隆重推出AJAX。


    什么是AJAX,我们可以先把这四个英文字母拆分开来,他们分别代表的意思为:A(Asynchronous——异步的)、J(JavaScript)、A(And)、X(XML)


    简单地说一下AJAX的起源和背景:IE5时率先在JavaScript中引入了ActiveX对象(API),使得JavaScript可以直接发起HTTP请求,随后被多个浏览器跟进和模仿后,最后W3C给这个API取名为XMLHttpRequest,并正式纳入W3C规范。
    顺便提一下,在XMLHttpRequest纳入W3C规范的一年后,Google利用这个API推出了Gmail(不用刷新整个网页,是局部更新的),在当时惊动了整个互联网。


    AJAX的技术特点:
1.使用XMLHttpRequest来发送请求。
2.服务器返回XML格式的字符串,返回XML格式的原因是因为当时只有XML是比较容易做到的一种数据传输格式,在这之后基本都开始使用JSON格式了。
3.JavaScript解析XML,并局部更新网页。


    话不多说,我们直接来看看这个API是怎么样使用的:

let request=new XMLHttpRequest()
request.open('GET','/xxx') //这里可以通过改变第一个参数,来发送PUT、GET、POST和DELETE请求
request.onreadystatechange=()=>{ console.log(request.readyState) }
request.send()

    上述代码中,打印出来的readyState表示请求的状态码,每次发起请求后,状态码都会依次从0~4经过,每个状态码的具体代表的含义请看MDN
    在0~4状态码中,2和3状态码由于存在时间很短,因此很难捕捉得到,而状态码4表示整个请求过程已经完毕,响应已经下载完成。之后我们可以通过let string=request.responseText来获取响应的内容,这里值得注意的是,获取到的响应的内容永远只能为字符串。
    当然我们不是一定可以获取到响应内容的,因为请求是存在失败的可能的,因此我们可以通过request.status来获取HTTP的状态码来判断请求的情况。

if (request.readyState===4){
    console.log('请求响应都已经完毕了')
    if (request.status>=200 && request.status<300){
        console.log('说明请求成功')
    } else if (request.status>=400){
        console.log('说明请求失败')
    }
}

    另外,XMLHttpRequest是可以自主设置请求头的,使用XMLHttpRequest.setRequestHeader(key,value)即可,这是设置HTTP请求头部,即请求的第二部分的办法,此方法必须在open()方法和send()方法之间调用。如果同一请求头设置多次,则会合并成一个多个值的请求头,这里值得注意的是,一些不安全的请求头是不能设置的,这些请求头有哪些,需要读者自己去尝试~
    这样看下来,好像AJAX很好用嘛,通过简单的API操作,就可以达到发送请求和获取响应的目的,比起JSONP来说,的确是方便了很多,但是,AJAX也有着一个突出的特点:正常情况下,无法跨域发送请求!!!


    AJAX会被同源策略所限制(同源策略的具体介绍请点击此处阅读),跨域的JavaScript不能发送AJAX请求,只有“协议+端口+域名”完全一模一样的情况下才允许发送AJAX请求。

1.http://baidu.com 不可以向 http://www.baidu.com 发送AJAX请求
2.http://baidu.com:80 不可以向 http://baidu.com:81 发送AJAX请求

    之所以说这是AJAX的“特点”,而不是“缺点”,这是因为如果没有了同源策略的限制,就没有任何隐私可言了,因为若没有了这种限制,像支付宝余额、QQ空间的好友列表这些信息均可以被他人读取,而之所以form表单这些可以跨域发送请求,那是因为他们会刷新页面,刷新了页面,旧的页面就不存在了,这样就能保证用户的隐私了。因此AJAX的这种“特点”的存在,十分有必要,也十分重要。


    可是,有的时候我们依然需要发送跨域请求,但我们又想使用AJAX,怎么办呢?
    那就使用CORS吧~CORS的全称是Cross-Origin Resource Sharing,具体的使用方法是,在跨域请求的服务器端写入以下代码

response.setHeader('Access-Control-Allow-Orign','要跨域访问的网址')

    这样该网址就能跨域向该服务器发起AJAX请求了~




    那么接下来进入我们的下一个重头戏,模拟JQuery封装AJAX的过程

window.jQuery.ajax=function({url,method,body,successFn,errorFn,headers}){
    let request=new XMLHttpRequest()
    request.open(method,url)
    request.onreadystatechange=function(){
        if (request.readyState===4){
            if (request.status>=200 && request.status<300) {
                successFn.call(undefined,request.responseText)
            } else {
                errorFn.call(undefined,request)
            }
        }
    }
    request.send(body)
}
$('#button').on('click',function(){
    window.jQuery.ajax(
        'http://127.0.0.1:8888/pay',
        'get',
        null,
        (responseText)=>{
            console.log(responseText)
            let string=responseText
            let object=window.JSON.parse(string)
            amount.textContent=object.left
            alert('请求成功')
        },
        (request)=>{
            console.log(request)
            alert('请求失败')
        },
        null
    )
})

    以上是对AJAX的普通封装,以上封装存在着两个很明显的缺点:
1.每个参数的位置是确定的,因此难以记住,容易混淆。
2.GET请求一般没有body参数,只能用null代替。


    那么我们先看如何改进第一个问题,解决方法:传入一个对象

window.jQuery.ajax=function(options){
    let method=options.method
    let url=options.url
    ...
}
$('#button').on('click',function(){
    window.jQuery.ajax({
        url:'http://127.0.0.1:8888/pay',
        method:'get',
        succeessFn:(responseText)=>{
            console.log(responseText)
            let string=responseText
            let object=window.JSON.parse(string)
            amount.textContent=object.left
            alert('请求成功')
        },
        errorFn:(request)=>{
            console.log(request)
            alert('请求失败')
        }
    })
})

    但这样写代码太丑了,每次传进一个对象,都要把对象的键対值重新抽出来赋值,于是我们想到使用ES6的解构赋值的技巧:

let method=options.method
let body=options.body
let successFn=options.successFn
//等价于
let {method,body,successFn}=options

    于是乎代码就变成了:

window.jQuery.ajax=function({url,method,body,successFn,errorFn,headers}){
    ...
}
$('#button').on('click',function(){
    window.jQuery.ajax({
        url:'http://127.0.0.1:8888/pay',
        method:'get',
        succeessFn:(responseText)=>{
            console.log(responseText)
            let string=responseText
            let object=window.JSON.parse(string)
            amount.textContent=object.left
            alert('请求成功')
        },
        errorFn:(request)=>{
            console.log(request)
            alert('请求失败')
        }
    })
})

    再把这个封装升级一下,使它满足 Promise 规则

window.jQuery.ajax=function({url,method,body,successFn,errorFn,headers}){
    return new Promise(function(resolve,reject){
        let request=new XMLHttpRequest()
        request.open(method,url)
        request.onreadystatechange=function(){
            if (request.readyState===4){
                if (request.status>=200 && request.status<300) {
                    resolve.call(undefined,request.responseText)
                } else {
                    reject.call(undefined,request)
                }
            }
        }
        request.send(body)
    })
}
$('#button').on('click',function(){
    window.jQuery.ajax({
        url:'http://127.0.0.1:8888/pay',
        method:'get'
    }).then(
        (responseText)=>{
            console.log(responseText)
            let string=responseText
            let object=window.JSON.parse(string)
            amount.textContent=object.left
            alert('请求成功')
        },
        (request)=>{
            console.log(request)
            alert('请求失败')
        }
    )
})

    好了,大功告成!
    看到这里,相信你已经懂得如何使用原生JS来使用和封装AJAX了。那么我们这次的文章也就介绍到这里了。
    最后声明一下,封装过程一些属性的命名和jQuery中所封装的AJAX里的属性的命名可能并不一致,因此读者在使用jQuery封装下的AJAX要以其官网文档内声明的属性为准~


    再次预告一下~下一次的文章将为大家讲述:JSONP的安全问题你了解过吗?



本教程版权归宣泽彬所有,转载须说明来源

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

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,460评论 1 45
  • AJAX 原生js操作ajax 1.创建XMLHttpRequest对象 var xhr = new XMLHtt...
    碧玉含香阅读 3,192评论 0 7
  •   2005 年,Jesse James Garrett 发表了一篇在线文章,题为“Ajax: A new App...
    霜天晓阅读 888评论 0 1
  • [cp]听说 自由才是禁锢内心最终追求 原来 那些固执压制往往已成为习惯 自以为那是稳定正常 其实它阻挡了外面的花...
    听说那个梦很遥远阅读 140评论 0 0
  • 顺着来时的方向,我一直往前走,一直走,我不知道我走了多久,过了多少个红绿灯,穿过了几条街,和几个人擦肩而过。雨有一...
    艾斯阿珍阅读 125评论 0 0