AJAX(3)

XMLHttpRequest对象简介

纲要

XMLHttpRequest 是一个内建的浏览器对象,Ajax技术的核心就是XMLHttpRequest 对象。

jQuery中的 $.ajax()$.get()$.post() 的底层实现,就是 XMLHttpRequest

历史

小结

  • XMLHttpRequest 简称 XHR 对象,是一个浏览器内置对象,目前,所有的浏览器均支持这个对象。

  • 它的作用是可以实现Ajax请求,Ajax技术的核心就是XMLHttpRequest 对象。

实现Ajax的GET请求

步骤

  1. 创建xhr对象。

  2. 注册 xhr.onreadystatechange 事件。在 readystatechange 函数中,接收响应结果。

  3. 调用open方法,初始化一个请求,此方法用于配置请求方式和url。

  4. 调用send方法,发送请求。

基础代码

// 1. 创建xhr对象
var xhr = new XMLHttpRequest();
​
// 2. 注册 xhr.onreadystatechange 事件,当Ajax请求**成功**后,会触发onload函数。在 readystatechange 函数中,接收响应结果。
xhr.onreadystatechange = function () {
    // 使用 xhr.response 接收响应结果
    var res = xhr.responseText;
}
​
// 3. 调用open方法,设置请求方式及请求的url地址
// xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks');
xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks?appkey=13200008888');
​
// 4. 最后,调用send方法,发送这次ajax请求
xhr.send();

请求参数

重要:如果传递请求参数,请求参数要以查询字符串形式拼接到url后面。

形如:url?id=1&appkey=13200008888

GET和DELETE请求,需要以这种方式来传递参数。

其他说明

API兼容性
XMLHttpRequestIE7+ 支持
open所有浏览器均支持
send所有浏览器均支持
onreadystatechange所有浏览器均支持
responseText所有浏览器均支持

了解 XMLHttpRequest 对象所有API的兼容性,点击这里

实现Ajax的POST请求

步骤

(比GET请求多了一行代码)

  1. 创建xhr对象。

  2. 注册 xhr.onreadystatechange 事件。在 readystatechange 函数中,接收响应结果。

  3. 调用open方法,初始化一个请求,此方法用于配置请求方式和url。

  4. 调用setRequestHeader方法,设置请求头。

  5. 调用send方法,发送请求。

基础代码

// 1. 创建xhr对象
var xhr = new XMLHttpRequest();
​
// 2. 注册 xhr.onreadystatechange 事件,当Ajax请求**成功**后,会触发onload函数。在 readystatechange 函数中,接收响应结果。
xhr.onreadystatechange = function () {
    // 使用 xhr.response 接收响应结果
    var res = xhr.responseText;
}
​
// 3. 调用open方法,设置请求方式及请求的url地址
xhr.open('POST', 'http://www.itcbc.com:3006/api/addbook');
​
// 4. 调用setRequestHeader,设置请求头,目的是告知服务器以何种方式解析请求体
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
​
// 5. 最后,调用send方法,发送这次ajax请求
xhr.send('bookname=西游记&author=唐僧&publisher=大唐出版社&appkey=13200008888');

请求体

重申一下,POST请求的参数,称之为请求体。

和GET请求一样,请求体也要写成查询字符串格式,不同之处是,请求体做为send方法的参数发送。

其他说明

API兼容性
setRequestHeader所有浏览器均支持

setRequestHeader 方法用于设置请求头,格式如下:

xhr.setRequestHeader('名称', '值');
  • 设置的请求头可以在 network 面板 > Headers > Request Headers 中查看。

  • 大部分请求头由浏览器管理,不允许我们修改。所以我们无需关心。

  • 一旦设置了请求头,就无法撤销了。

Content-Type

  • 只有POST、PUT请求,才需要设置Content-Type请求头

  • 这里设置的 Content-Type ,作用是告知服务器,浏览器提交的数据是何种类型的。

    • 值为:application/x-www-form-urlencoded(需要自己指定) ,表示客户端提交的是查询字符串

    • 值为:application/json(需要自己指定) ,表示客户端提交的是 JSON 字符串

    • 值为:multipart/form-data(xhr对象会自动设置),表示客户端提交的是 FormData 对象

对请求参数进行编码

什么是URL编码?

  • 把中文和部分特殊符号转成 URL的标准格式 ,这就是url编码

  • 如,把“中文” 进行url编码后得到 “%E4%B8%AD%E6%96%87”

为什么要对请求参数进行编码

  • RFC文档规定,只有字母和数字[0-9a-zA-Z]、一些特殊符号“$-_.+!*’(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。

  • 对于Unicode字符,RFC文档建议使用utf-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码,也就是所谓的 URL编码

编码能够解决的问题

  • 乱码问题(浏览器使用utf-8、服务器使用其他编码,传输数据的时候,就会乱码)

  • 提交的内容有特殊符号问题,比如添加一本书,书名是 “红&黑”

如何进行URL编码

JS提供了内置编码解码函数

  • 编码:encodeURIComponent('西游记')

  • 解码:decodeURIComponent("%E8%A5%BF%E6%B8%B8%E8%AE%B0");

具体查看手册:JavaScript 全局参考手册

小结

无论是GET请求还是POST请求,向服务器传递参数的时候,必须要对参数进行编码。这里的参数包括参数名和值。

比如,参数为 shu ming=红&黑

  • 参数名中有空格,需要编码;

  • 值有中文,且有歧义,需要编码;

readyState属性

Ajax从创建xhr对象开始,一直到完全接收服务器返回的结果为止;我们可以把整个请求响应过程划分为5个阶段。并且可以使用 xhr.readyState 属性检测当前请求执行到哪个阶段了。

readyState属性值为一个数字,不同的数字表示Ajax的不同状态。

  • 如果状态值为0(xhr.readyState === 0),初始状态,表示xhr对象一定创建了。

  • 如果状态值为1(xhr.readyState === 1),表示open一定调用了

  • 如果状态值为2(xhr.readyState === 2),表示send一定调用了,并且已经接收到响应头。

  • 如果状态值为3(xhr.readyState === 3),表示正在接收服务器返回的数据(可能已接收完毕,也可能正在接收中,取决于数据量的大小)

  • 如果状态值为4xhr.readyState === 4),表示Ajax请求~响应过程完成

值为0、1、2、3的时候,基本上不用关心。主要关心值为4的时候,因为这个时候表示Ajax请求~响应过程完成了,如果成功的结束了,则可以完全接收服务器响应的结果。

下面在创建xhr对象后和onreadystatechange事件内部分别输出 xhr.readyState 可以分别得到 0 、1、2、3、4。

// 1. 创建xhr对象
var xhr = new XMLHttpRequest();
​
console.log(xhr.readyState); // ===> 0
​
// 2. 注册 xhr.onreadystatechange 事件,当Ajax请求**成功**后,会触发onload函数。在 readystatechange 函数中,接收响应结果。
xhr.onreadystatechange = function () {
    console.log(xhr.readyState); // ===> 1/2/3/4
    // 使用 xhr.response 接收响应结果
    var res = xhr.responseText;
}
​
// 3. 调用open方法,设置请求方式及请求的url地址
// xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks');
xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks?appkey=13200008888');
​
// 4. 最后,调用send方法,发送这次ajax请求
xhr.send();

onreadystatechange事件

介绍

onreadystatechange 翻译过来是 当Ajax的请求状态改变的时候

所以,它是配合上述的 readyState 使用的事件。

事件具体的触发时机如下

  • readyState属性值改变的时候

    • 0 --> 1

    • 1 --> 2

    • 2 --> 3

    • 3 --> 4

  • 接收到的数据量改变的时候,此时 readyState 的值保持为3,但也会触发 onreadystatechange 事件(发生在分块接收大量数据的时候)

所以,绑定的onreadystatechange事件,可能会触发多次。

完整代码

前文提到,onload有浏览器兼容问题,如果你的项目需要支持低版本的浏览器,那么可以使用 onreadystatechange事件代替onload事件。

由于onreadystatechange事件可能会触发多次,所以需要在事件中加入判断,已保证准确的接收到响应结果。

// 1. 创建xhr对象
var xhr = new XMLHttpRequest();
// IE6 创建对象 var xhr = new ActiveXObject('Microsoft.XMLHTTP');
​
// 2. 使用onreadystatechange代替onload
xhr.onreadystatechange = function () {
    // 判断Ajax请求是否完成
    if(xhr.readyState === 4) {
        // 还要根据响应状态码判断,请求是否成功
        if (xhr.status === 200) {
            console.log(xhr.responseText);
        } else {
            console.log('请求失败')
        }
    }
}
​
// 3. 调用open方法,设置请求方式及请求的url地址(如有参数,拼接到url后面)
xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks?appkey=13200008888');
​
// 4. 最后,调用send方法,发送这次ajax请求
xhr.send();

设置HTTP请求时限

  • timeout -- Level 2 新增,IE8+支持,用于设置请求的超时时间,单位是毫秒

  • ontimeout -- Level 2 新增,IE10+支持,如果请求超时了,会触发 ontimeout 事件

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
  if (this.readyState === 4 && this.status === 200) {
    console.log(this.responseText);
  }
}
xhr.timeout = 30; // 单位是毫秒
// 当请求超时之后,会触发下面的函数
xhr.ontimeout = function () {
    alert('请求超时,请刷新重试');
}
xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks?appkey=13200008888');
xhr.send();

xhr2新增事件

  • ontimeout -- 请求超时之后,触发的事件

  • onload -- 请求成功后触发的事件(因为已经表示成功后触发了,所以事件内部就不要加if判断了)

  • onerror -- 请求失败后触发的事件,比如网络不通造成的请求发送失败

  • onloadstart -- 请求开始的时候,触发的事件

  • onloadend -- 请求完成后触发的事件,这里的完成包括成功和失败

  • onprogress -- 客户端下载(接收)数据的时候,触发的事件

FormData对象

介绍

Form是表单,Data是数据。猜测,它和表单数据有关系。

FormData是h5出现之后,新增的一个对象。用于管理表单数据。IE10+支持。

创建的FormData对象,可直接通过 xhr.send(FormData对象) 提交给服务器的接口。

基本语法

var fd = new FormData([form]); // 参数是表单的DOM对象,可选

FormData的API:(除了append方法IE10支持外,其他方法IE均不支持

  • append('key', 'value'); -- 向对象中追加数据

  • set('key', 'value'); -- 修改对象中的数据

  • delete('key'); -- 从对象中删除数据

  • get('key') -- 获取对象中的数据

  • getAll('key') -- 获取指定key的全部数据

  • forEach() -- 遍历对象中的数据

  • ....

<form action="">
    <input type="text" name="username"><br />
    <input type="password" name="pwd"><br />
    <input type="radio" name="sex" value="nan">
    <input type="radio" name="sex" value="nv"><br />
​
    <button>提交</button>
</form>
​
<script>
    document.querySelector('form').onsubmit = function (e) {
        e.preventDefault();
​
        // 使用FormData收集表单数据
        var fd = new FormData(this); // 传入表单的DOM对象
​
        // append向fd对象中追加数据
        fd.append('age', 20); // 追加一个age
        fd.append('username', 'lisi'); // 追加一个username
​
        // set修改fd中的数据
        fd.set('sex', 'yao'); // 修改sex
​
        // get用于获取一个值
        console.log(  fd.get('username')  ); // 获取到一个username的值
        console.log(  fd.getAll('username')  ); // 获取到全部username的值
​
        // console.log(fd); // 输出fd没用,看不到数据
        // 只能通过forEach来检查对象中有哪些数据
        fd.forEach(function (val, key) {
            // console.log(key, val);
        });
​
    }
</script>

提交FormData

FormData本就是配合XHR对象一起使用的

前面我们收集到了很多值,现在,我们可以通过Ajax,将这些值提交给接口。

  • 只能通过POST方式提交FormData对象

  • 不能设置Content-Type请求头,因为当提交FormData的时候,浏览器会自动设置这个请求头。

<form action="">
    姓名:<input type="text" name="username"><br>
    年龄:<input type="text" name="age"><br>
    身高:<input type="text" name="height"><br>
    <button>提交</button>
</form>

<script>

    document.querySelector('form').onsubmit = function (e) {
        e.preventDefault();
        var fd = new FormData(this);

        // ajax提交数据到接口
        var xhr = new XMLHttpRequest();
        xhr.onload = function () {
            console.log(this.responseText);
        }
        xhr.open('POST', 'http://www.itcbc.com:3006/api/formdata');
        // xhr.setRequestHeader(); // 使用FormData,不要设置请求头;写了请求头,反而会报错
        xhr.send(fd);
    }
</script>

如果提交FormData数据给接口,需要接口的支持。比如添加图书、添加评论接口都不支持提交FormData数据。

注意事项(必看)

  • 使用FormData,要求表单各项必须有name属性,因为FormData也是根据表单各项的name属性获取值的

  • 不能收集禁用状态的值。

  • 实例化 FormData对象,传入表单的DOM对象,可以快速收集到表单各项值。

  • 可以收集文件信息可以完成文件上传

  • 如果要检查FormData中有哪些值,需要使用forEach遍历

  • 如果需要动态添加或修改FormData中的值,可以调用 FormData的append或set方法。

上传文件并显示进度条

实现过程

  1. 先完成提交文件,即使用FormData获取文件域的内容,然后Ajax提交FormData对象给接口。

  2. 再能够上传文件的基础之上,注册xhr.upload.onprogress事件,监听上传进度变化,制作进度条

参考代码

<form>
	<input type="file" name="avatar">
	<button>上传</button>
</form>

<!-- 设置一个进度条,这里使用h5新标签,开始隐藏 -->
<progress max="0" value="0" style="display: none"></progress>


<script>
    document.querySelector('form').onsubmit = function (e) {
        e.preventDefault();
        // 使用FormData收集输入框的值(这里是选择的图片)
        var fd = new FormData(this);

        // ajax提交fd对象
        // 接口文档,查看ppt即可
        var xhr = new XMLHttpRequest();
        
        /*************************************************/
        /*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
        // 找到 进度条标签 
        var progress = document.querySelector('progress');
        // 注册上传监听事件
        xhr.upload.onprogress = function (e) {
            progress.style.display = 'block';
            progress.max = e.total; // 文件总大小,单位字节
            progress.value = e.loaded; // 已经上传了多少字节
        }
        /*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/
        /************************************************/
        
        xhr.onload = function () {
            console.log(this.responseText);
        }
        xhr.open('POST', 'http://www.itcbc.com:3006/api/formdata');
        xhr.send(fd);

    }
</script>

注意,上传进度使用xhr.upload.onprogress事件;下载进度使用xhr.onprogress事件;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值