XMLHttpRequest 对象
XHR 1.0 是一个内建的浏览器对象,可以实现 Ajax 请求,Ajax技术的核心就是XMLHttpRequest 对象。
GET是在 open 里传参,POST是在 send 里传参。
原生 Js 实现基本的 GET 请求
获取所有数据
// 1.创建XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 2.监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
// 2.1 当 Ajax 请求响应完后,再拿到服务器响应的数据
if (xhr.readyState == 4) {
// 2.2 用 JSON.parse 将结果转成对象
console.log( JSON.parse(xhr.responseText) );
}
}
// 3.设置请求方式和请求地址
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks');
// 4.发送 ajax 请求
xhr.send();
获取指定数据
// 创建 xhr 对象
var xhr = new XMLHttpRequest();
// 注册事件
xhr.onreadystatechange = function () {
// 当 Ajax 请求响应完后,再拿到服务器响应的数据
if (xhr.readyState == 4) {
// 用 JSON.parse 将结果转成对象
console.log( JSON.parse(xhr.responseText) );
}
}
// 设置请求头,并设置要获取的数据id
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks?id=1');
// 提交请求体
xhr.send();
删除数据
删除 id 为 5686 的数据。
btns[2].addEventListener('click', (e = window.event) => {
// 创建 xhr 对象
var xhr = new XMLHttpRequest();
// 注册事件
xhr.onreadystatechange = function () {
var res = xhr.responseText;
if (xhr.readyState == 4) {
// 用 JSON.parse 将结果转成对象
console.log( JSON.parse(xhr.responseText) );
}
}
xhr.open('get', 'http://www.liulongbin.top:3006/api/delbook?id=5686');
// 提交请求体
xhr.send();
});
原生 Js 实现基本的 POST 请求
和 GET请求有以下区别:
在open 和 send 之间,必须设置请求头,通过 Content-Type 标识提交的数据类型(编码格式)。
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
提交的请求体,不是拼接到url后面,而是当做send方法的参数。
xhr.send('bookname=史记&author=司马迁&publisher=北京大学出版社');
添加数据
// 创建 xhr 对象
var xhr = new XMLHttpRequest();
// 注册事件
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
// 用 JSON.parse 将结果转成对象
console.log( JSON.parse(xhr.responseText) );
}
}
xhr.open('post', 'http://www.liulongbin.top:3006/api/addbook');
// 设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 提交请求体
xhr.send("bookname=书名&author=作者&publisher=出版社");
原生 Js 进行封装
还原 jQuery 中的 get 和 post 方法的封装。
分析:
- 函数只有一个参数,是一个对象。
- 包括:type、url、data、success 四个属性。
- GET 和 POST 请求,都需要创建 xhr 对象,都需要设置 onreadystatechange 事件。
- 当得到响应结果后,调用 success 函数后,把结果传递给 success 函数。
- 需要把对象形式的请求参数,转换成查询字符串。
- 由于GET和POST的 “open”和 “send”不一样,所以判断,然后分开写。
- 优化(默认GET、大小写等等)。
// 调用
ajax({
url: 'http://www.liulongbin.top:3006/api/getbooks',
type: 'get',
data: { id: 1 },
success: function (res) {
console.log(res);
}
})
// 封装原生 Js 方法
function ajax(option) {
// 1.将对象参数 转成 相应格式的字符串
var params = objectToString(option.data);
var type = option.type;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 判断类型,返回
if (type == 'get') {
xhr.open(type, `${option.url}?${params}`);
xhr.send();
} else {
xhr.open(type, option.url);
xhr.send(params);
}
}
// 请求参数
function objectToString(data) {
var list = [];
for (var key in data) {
list.push(`${key}=${data[key]}`);
}
return list.join('&');
}
readyState 属性
Ajax 从创建 xhr 对象开始,一直到完全接收服务器返回的结果为止;我们可以把整个请求响应过程划分为5个阶段。并且可以使用
xhr.readyState
属性检测当前请求执行到哪个阶段了。
readyState
属性值为一个数字,不同的数字表示 Ajax 的不同状态。
属性值 | 状态 |
---|---|
xhr.readyState === 0 | 初始状态,表示 xhr 对象一定创建了 |
xhr.readyState === 1 | 表示 open 一定调用了 |
xhr.readyState === 2 | 表示 send 一定调用了,并且已经接收到响应头 |
xhr.readyState === 3 | 表示正在接收服务器返回的数据(可能已接收完毕,也可能正在接收中,取决于数据量的大小) |
xhr.readyState === 4 | 表示 Ajax 请求响应过程完成 |
status 属性
status 属性表示 http 状态码,是一个数字,代码指示特定 HTTP 请求是否已成功完成。
相应分类:
- 信息响应(100–199)
- 成功响应(200–299)
- 重定向(300–399)
- 客户端错误(400–499)
- 服务器错误 (500–599)
常用状态码:
- 200 OK - 请求成功
- 400 Bad Request - 1、语义有误,当前请求无法被服务器理解。2、请求参数有误。
- 401 Unauthorized - 当前请求需要用户验证。
- 404 Not Found - 请求失败,请求所希望得到的资源未被在服务器上发现。
- 500 Internal Server Error - 服务器遇到了不知道如何处理的情况。
URL 编码解码
把中文和部分特殊符号转成 URL 的标准格式,这就是 url 编码。
作用:解决乱码问题。
编码
encodeURIComponent()
var name = '张三';
var r = encodeURIComponent(name);
console.log(r); // "%E5%BC%A0%E4%B8%89"
解码
decodeURIComponent()
var r = "%E5%BC%A0%E4%B8%89";
console.log( decodeURIComponent(r) ); // 张三
XMLHttpRequest level 2
XHR 2.0 对XMLHttpRequest进行了扩展。
timeout 请求超时限制设置
timeout 和 ontimeout
// 1.设置请求超时时间,单位是毫秒
xhr.timeout = 30;
// 2.设置超时返回的内容
xhr.ontimeout = function () {
console.log('请求超时了');
}
// 1.创建 xhr 对象
let xhr = new XMLHttpRequest();
// 2.设置请求方式
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks');
// 3.发送请求
xhr.send();
// 4.设置请求超时时间,单位是毫秒
xhr.timeout = 1000;
// 5.设置超时返回的内容
xhr.ontimeout = function () {
console.log('请求超时了');
}
// 6.监听
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText)
}
}
onload 事件
onload 事件,其你去成功时触发,可以代替
onreadystatechange
事件。使用 onload 代替
onreadystatechange
,里面不用加判断,因为 onload 本身就是在请求成功时触发的。
xhr.onload = function() {
// 成功响应后,获取响应结果
console.log(JSON.parse(this.responseText));
}
// 1.创建 xhr 对象
let xhr = new XMLHttpRequest();
// 2.设置请求方式
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks');
// 3.发送请求
xhr.send();
// 4.设置请求超时时间,单位是毫秒
xhr.timeout = 1000;
// 5.设置超时返回的内容
xhr.ontimeout = function () {
console.log('请求超时了');
}
// 6.监听
xhr.onload = function() {
// 成功响应后,获取响应结果
if (xhr.status == 200) {
console.log(JSON.parse(this.responseText));
}
}
onerror 事件
在请求失败时触发。断网情况下触发。
xhr.onerror = function () {
console.log('请求失败,请检查当前网络环境');
}
// 1.创建 xhr 对象
let xhr = new XMLHttpRequest();
// 2.设置请求方式
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks');
// 3.发送请求
xhr.send();
// 4.监听
xhr.onload = function() {
// 成功响应后,获取响应结果
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 5.请求失败
xhr.onerror = function () {
console.log('请求失败,请检查当前网络环境');
}
onprogress 事件
在请求完成之前周期性调用的函数。readyState 为 3 时触发。
作用:可以使用 onprogress 事件,获取数据的接收(下载)进度。
xhr.onprogress = function (event) {
// 已传输的数据量
event.loaded;
// 总共的数据量
event.total;
}
// 1.创建 xhr 对象
let xhr = new XMLHttpRequest();
// 2.设置请求方式
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks');
// 3.发送请求
xhr.send();
// 4.监听
xhr.onload = function() {
// 成功响应后,获取响应结果
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 5.请求失败
xhr.onerror = function () {
console.log('请求失败,请检查当前网络环境');
}
// 6.进度
xhr.onprogress = function (event) {
// 已传输的数据量
event.loaded;
// 总共的数据量
event.total;
}
onloadstart 事件
下载数据之前触发。
放在 open 和 send 之间。
xhr.onloadstart = function () {
console.log('下载数据之前');
}
onloadend 事件
下载数据完成之后需触发。
放在 open 和 send 之间。
xhr.onloadend = function () {
console.log('下载数据完成之后');
}
let xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks');
xhr.onloadstart = function () {
console.log('下载数据之前');
}
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
xhr.onloadend = function () {
console.log('下载数据完成之后触发')
}
xhr.send();
FormData 对象
h5出现之后,新增的一个对象。用于管理表单数据。
创建 FormData 对象,可直接通过 xhr.send (FormData对象) 提交给服务器的接口。
// 获取元素
let form = document.querySelector('form');
// 实例化 formData 对象,传入form
let formData = new FormData(form);
xhr.open('post', '要提交的地址');
xhr.send(formData);
创建表单时,一定要设置 name 属性,传数据时要使用 name 属性当做 键名 来使用。
name 值是什么,键名就是什么。
<html>
<body>
<form>
<input type="text" name="username" id="username" >
<input type="password" name="pwd" id="pwd" >
<input type="button" id="btn" >
</form>
</body>
<script>
// 获取元素
let form = document.querySelector('form');
let btn = document.querySelector('#btn');
btn.addEventListener('click', function (event) {
let xhr = new XMLHttpRequest();
// 实例化 formData 对象,传入form
let formData = new FormData(form);
xhr.open('post', 'http://121.5.153.184:3000/formData');
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 提交数据
xhr.send(formData);
});
</script>
</html>
API 方法
append 方法
向对象中追加数据。
会追加一个自定义的属性。formData.append('key', 'value');
// 获取元素
let form = document.querySelector('form');
let btn = document.querySelector('#btn');
btn.addEventListener('click', function (event) {
let xhr = new XMLHttpRequest();
// 实例化 formData 对象,传入form
let formData = new FormData(form);
formData.append('age', 18);
xhr.open('post', 'http://121.5.153.184:3000/formData');
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 提交数据
xhr.send(formData);
});
set 方法
修改对象中的数据。
有同名属性,则修改该属性的值;没有同名属性,则新增该属性。
formData.set('key', 'value');
// 获取元素
let form = document.querySelector('form');
let btn = document.querySelector('#btn');
btn.addEventListener('click', function (event) {
// 实例化 formData 对象,传入form
let formData = new FormData(form);
formData.set('username', '李四');
let xhr = new XMLHttpRequest();
xhr.open('post', 'http://121.5.153.184:3000/formData');
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 提交数据
xhr.send(formData);
});
delete 方法
从对象中删除数据。
删除指定的属性。
formData.delect('key');
// 获取元素
let form = document.querySelector('form');
let btn = document.querySelector('#btn');
btn.addEventListener('click', function (event) {
// 实例化 formData 对象,传入form
let formData = new FormData(form);
formData.delete('username');
let xhr = new XMLHttpRequest();
xhr.open('post', 'http://121.5.153.184:3000/formData');
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 提交数据
xhr.send(formData);
});
get 方法
获取指定 key 的一项数据。
formData.get('key');
// 获取元素
let form = document.querySelector('form');
let btn = document.querySelector('#btn');
btn.addEventListener('click', function (event) {
// 实例化 formData 对象,传入form
let formData = new FormData(form);
console.log( formData.get('username') );
let xhr = new XMLHttpRequest();
xhr.open('post', 'http://121.5.153.184:3000/formData');
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 提交数据
xhr.send(formData);
});
getAll 方法
获取指定 key 的全部数据,返回值是数组。
formData.getAll('key');
forEach 方法
遍历对象中的数据。
formData.forEach(item => { console.log(item); })
// 获取元素
let form = document.querySelector('form');
let btn = document.querySelector('#btn');
btn.addEventListener('click', function (event) {
// 实例化 formData 对象,传入form
let formData = new FormData(form);
formData.forEach(item => {
console.log(item);
})
let xhr = new XMLHttpRequest();
xhr.open('post', 'http://121.5.153.184:3000/formData');
xhr.onload = function () {
if (xhr.status == 200) {
console.log(JSON.parse(xhr.responseText));
}
}
// 提交数据
xhr.send(formData);
});
文件上传进度监听
待补充
CORS 跨域资源共享
待补充
JSON
本质是字符串,结构和对象差不多。
键名必须要加双引号,不能写 函数 、null 和 undefined。
{
"name": "张三",
"age": 18,
"arr": [10, 20, 30, 40],
"bl": true,
}
JSON字符串和JS数据转换
JS ----> JSON(序列化):JSON.stringify( JS数据 );
JSON ----> JS (反序列化):JSON.parse( JSON字符串 );
var data = {
"name": "张三",
"age": 18,
"arr": [10, 20, 30, 40],
"bl": true,
}
// js 数据序列化为字符串
var jsonStr = JSON.stringify(data);
// 结果:"{"name":"张三","age":18,"arr":[10,20,30,40],"bl":true}"
// 反序列化成对象
JSON.parse(jsonStr);