为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
JavaScript

    上篇文章我们说到了什么是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.methodlet body=options.bodylet 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的安全问题你了解过吗?



作者:宣泽彬
链接:https://www.jianshu.com/p/4d371de8e8ff


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消