原生js的Ajax请求详解

自古美人都是妖i 提交于 2019-12-22 11:06:56

Ajax是可以用来与服务器进行通讯的一种技术,它可以在不刷新页面的情况下进行异步通讯并获得返回结果。

Ajax常用的请求方式有两种,GET和POST,接下来将详细给出这两种请求方式的异同,以及Ajax使用时需要注意的地方。

1 GET请求

get请求一般用在向服务器请求某些资源,例如请求一段文章,或者一张图片等等。

下面是完整的get请求的方式 我们可以看到,在获得XMLHttpRequest对象的时候我们进行了一个判断,这是因为

所有现代浏览器 (IE7+、Firefox、Chrome、Safari 以及 Opera) 都内建了 XMLHttpRequest 对象,

而IE6或以下的需要用到ActiveXObject才能构建,所以需要进行判断,不过这个判断不加似乎也没事,因为现在几乎不可能有人

使用IE6以下的浏览器了

    let url = "http://localhost/StarRing/public/StarRing.php/StarRing/Articles/AjaxGet";
    
    //1 定义xmlHttpRequset对象
    let xmlHttp;
    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    //2 设置请求方式以及URL 第三个参数表示是否进行异步请求 默认为true,若写个false则是同步请求
    //不过一般没人会这么做
    xmlHttp.open("GET", url, true);

    //3 设置监听请求状态变化的函数 
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            let responseText = JSON.parse(xmlHttp.responseText);
            console.log(responseText);
        }
    };

    //4 发送请求
    xmlHttp.send();

我们来看看请求结果,我们可以看到,已经请求到了数据,这里需要注意,我请求的是我自己的Thinkphp后台,你们也可以去请求自己的后台。

2 POST 

大家可以看到 post请求其实和get请求基本类似 不过需要设置请求头而已,这一步get请求不需要,并且大家应该注意到了,我的send里面写了个参数    "name=张三"    这是因为我的php后台需要收一个参数,而这也正是post请求的一个传参的方式,这里我要强调的是,ajax默认不能发送json数据,它post的传参数是以键值对的形式存在的

例如 :"name=zhangsan&age=17&sex=1"

多个参数使用 "&" 符号拼接

    let url = "http://localhost/StarRing/public/StarRing.php/StarRing/Articles/AjaxPost";

    //1 定义xmlHttpRequset对象
    let xmlHttp;
    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    //2 设置请求方式以及URL
    xmlHttp.open("POST", url);

    //3 设置请求头 这一步只有post请求需要 而get请求不需要
    xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    //4 设置监听请求状态变化的函数
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            let responseText = JSON.parse(xmlHttp.responseText);
            console.log(responseText);
        }
    };

    //5 发送请求
    xmlHttp.send('name=张三');

来看看返回结果

 

3 状态码

大家可能注意到了,无论是post还是get,它都需要设置一个监听状态变化的函数,这是做什么呢?

这是因为ajax在请求的开始到结束是有自己的状态的。

    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            let responseText = JSON.parse(xmlHttp.responseText);
            console.log(responseText);
        }
    };

我们可以看到,判断了两种状态,这里readyState是ajax的准备状态,而status是http的响应状态码

readyState状态码

0 表示请求未初始化
1 已经与服务器建立好了链接
2 请求已经接受
3 正在处理请求
4 请求已经完成了,并且已将接收到了响应数据

HTTP的状态码
200 表示成功
304 请求成功 304和200都表示请求成功,只不过304请求的缓存数据
403 表示服务器拒绝请求
404 表示服务器地址未找到,这一般是服务器未开启,或请求地址有误
500 表示服务器的内部错误,这一般是服务的参数有误,或服务器代码写错了

这也就是我为什么在判断状态变化时,只有ajax的准备状态为4并且http的响应是200才算请求成功的原因。

4 踩坑

刚刚说了状态变化,现在我要告诉大家这里其实有个坑,如果我们在监听状态变化时,不仅仅写了 if 还加了 else子句的话,那么你的代码就可能会出现无法想象的错误,并且你可能很难找到

    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            let responseText = JSON.parse(xmlHttp.responseText);
            console.log(responseText);
        }else{
            //请求失败的操作
            console.log("请求失败了")
        }
    };

我们可以这样请求一下,看看会返回什么

很奇怪,明明请求到了数据,但是请求失败的状态判断他也输出了,这是为什么呢?

其实主要是因为状态变化所导致的,我们需要明白一点

xmlHttp.onreadystatechange 这个函数,它是用来监听状态变化的函数,注意是状态变化,而我们刚刚说了,ajax有5种状态,也就是说它的状态会变四次 

0  1
1  2
2  3
3  4

 我们直接写个请求 ,来看看这四次是怎么变化的,大家可以看到,我总共在三个地方打印了状态的变化,第一处是刚刚创建时,

第二处是设置请求后时,第三处是在监听状态变化的函数里,这三处我用 A B C来标明

    let url = "http://localhost/StarRing/public/StarRing.php/StarRing/Articles/AjaxGet";

    //1 定义xmlHttpRequset对象
    let xmlHttp;
    if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    console.log("A-->",xmlHttp.readyState);

    //2 设置请求方式以及URL 第三个参数表示是否进行异步请求 默认为true,若写个false则是同步请求
    //不过一般没人会这么做
    xmlHttp.open("GET", url, true);
    console.log("B-->",xmlHttp.readyState);

    //3 设置监听请求状态变化的函数
    xmlHttp.onreadystatechange = function () {
        console.log("C-->",xmlHttp.readyState);
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            let responseText = JSON.parse(xmlHttp.responseText);
            console.log(responseText);
        }else{
            //请求失败了
            console.log("失败了");
        }
    };

    //4 发送请求
    xmlHttp.send();

然后我们来看看请求结果

结果一目了然,状态变化2和3和4都在同一个地方输出的,我们可以看到它的前缀都是 C-->,这也就是为什么我们写了else时,它会先执行两次else里面的内容,因为状态2 和 3 它也会进入到监听状态变化的函数中去,所以此时就会出现请求到了数据,但是失败的判断也会执行

所以,这是错误的例子

    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            let responseText = JSON.parse(xmlHttp.responseText);
            console.log(responseText);
        }else{
            //请求失败了
            console.log("失败了");
        }
    };

正确的操作应该是这样

这样就可以完美的监听到请求到底是成功了,还是失败了

    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4) {
            if(xmlHttp.status===200){
                let responseText = JSON.parse(xmlHttp.responseText);
                console.log(responseText);
            }else{
                //请求失败了
                console.log("失败了");
            }
        }
    };

我们可以看看,改成正确的操作之后的返回结果

可以看到 ,没有输出请求失败了。。

5 跨域 

先来看看这个错误

有些同学按照我刚刚的代码进行请求,可能会出现这种错误,很懵逼,明明代码没错,这是为什么呢,

这其实就是我们所说的跨域问题,那什么是跨域呢?

跨域本质上是由浏览器的同源策略所导致的问题,什么是同源策略,同源策略是浏览器的一种安全机制,

同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准。它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载。

这里的同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。 指一段脚本只能读取来自同一来源的窗口和文档的属性。

若协议 域名 端口 中有一个不同,就会出现跨域问题。

那么,为什么要有同源策略,我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

好,现在来说说怎么解决,我这里是直接在php后台设置了一个请求头,

    public function AjaxPost(){
        header('Access-Control-Allow-Origin:*');
        $name = input('name');
        $age = input('age');
        echo json_encode( array("code"=>1,"msg"=>"post请求--".$name."---".$age));
    }

没错 就是这段代码,它的意思大概就是允许所以客户端访问

header('Access-Control-Allow-Origin:*');

当然 解决办法不止这一种

 jsonp、 iframe、window.name、window.postMessage、服务器上设置代理页面

 这些方法都可以解决跨域问题。

好了,就写到这

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!