Ajax第四天
一、请求报文
1.什么是请求报文和响应报文:
客户端与服务器通信的过程是基于请求与响应的。其中: ①请求报文规定了客户端以什么格式把数据发送给服务器
②响应报文规定了服务器以什么格式把数据响应给客户端
2.请求报文由请求行(request line)、请求头部( header )、空行 和 请求体 4 个部分组成。
(注意:在浏览器中,GET 请求比较特殊,它只有请求头,没有请求体。在浏览器中,POST、PUT、PATCH、DELETE 请求既有请求头,又有请求体。)
3.响应报文由状态行、响应头部、空行 和 响应体 4 个部分组成。
4.URL参数
(1)常用的5种请求方式,都可以在URL后面携带请求参数。
(2)由于URL的长度有限制,所以请求参数一般都比较小,比如不能做文件上传
(3)常用的请求参数有两种写法
/api/xxx?参数=值&参数=值 (这种格式的字符串叫做查询字符串,所以这样的参数叫做查询参数)
/api/xxx/值/值 (Restful 风格的接口用这种格式的参数)
5.axios中 如何携带不同格式的请求参数
(1)第一种格式的参数:(/api/xxx?参数=值&参数=值)
// 直接写成查询字符串,并拼接到url后面
axios.get('/api/xxx?key=value&key=value')
// 按照axios的语法写,axios会帮我们转成查询字符串
axios.get('api/xxx', { params: { key: value, key: value } })
(2)第二种格式的参数:( /api/xxx/值/值)
// 只能自己拼接
axios.get('/api/xxx/100/zhangsan')
6.请求体
(1)除GET请求以外,其他4种常用的请求方式,都可以设置请求体。 (2)请求体的大小没有限制,所以可以提交大量的数据 (3)常用的请求体格式有如下三种:
参数=值&参数=值 (查询字符串格式)
'{ "id": 1, "name": "zs" }' (JSON格式)
new FormData() (FormData对象格式)
(4)请求的时候,设置了不同格式的请求体,需要一个对应的请求头
二、响应报文
1.http 响应状态码:
概念:http 响应状态码(Status Code)由三位数字组成,用来标识响应成功与否的状态。 作用:客户端浏览器根据响应状态码,即可判断出这次 http 请求是成功还是失败了。
2.常见的 http 响应状态码
3.http 响应状态码 Vs 业务状态码
(1)所处的位置不同:
①在响应头的状态行中所包含的状态码,或者请求列表中的Status,叫做“响应状态码”
②在响应体的数据中所包含的状态码(案例中叫做code),叫做“业务状态码”
(2)表示的结果不同:
①响应状态码只能表示这次请求的成功与否(成功地失败了)
②业务状态码用来表示这次业务处理的成功与否
(3)通用性不同: ①响应状态码是由 http 协议规定的,具有通用性。每个不同的状态码都有其标准的含义,不能乱用。
②业务状态码是后端程序员自定义的,不具有通用性。
三、原生Ajax
1.XMLHttpRequest:是浏览器内置的一个构造函数。
①作用:基于 new 出来的 XMLHttpRequest 实例对象,可以发起 Ajax 的请求。
②axios 中的 axios.get()、axios.post()、axios() 方法,都是基于 XMLHttpRequest(简称:XHR) 封装出来的!
③发起 Ajax 请求的核心对象:XMLHttpRequest
④怎样拿到服务器响应回来的数据?load 事件 和 xhr.response
2.请求时携带URL参数 或 提交请求体
// 将请求参数拼接到url后面
xhr.open('请求方式', 'http://www.itcbc.com/api/xx?id=1&username=zhangsan');
xhr.send( 请求体 );
3.提交请求体数据,需指定Content-Type头
当需要提交请求体数据时,需要在 xhr.open() 之后,调用 xhr.setRequestHeader() 函数,指定请求体的编码格式
// 根据请求体格式的不同,需设置对应的Content-Type头
xhr.setRequestHeader('Content-Type', '值')
5.原生Ajax
(1)创建 xhr对象
(2)调用 open方法 指定 请求类型,url
(3)发送出去 send
(4)监听onload 数据响应事件
// 1 创建 xhr对象
const xhr = new XMLHttpRequest();
// 2 调用 open方法 指定 请求类型,url
xhr.open("get", "http://www.itcbc.com:3006/api/getbooks");
// 3 发送出去 send
xhr.send();
// 4 监听onload 数据响应事件
xhr.addEventListener("load", function () {
// this
console.log("数据回来啦");
// console.log(this.response);
// 字符串转对象
const obj = JSON.parse(this.response);
console.log(obj);
// 对象转字符串
const objstr = JSON.stringify(obj);
console.log(objstr);
});
6.原生-get-携带参数
const xhr = new XMLHttpRequest();
xhr.open("get", "http://www.itcbc.com:3006/api/getbooks?appkey=123123");
xhr.send();
xhr.addEventListener("load", function () {
obj = JSON.parse(this.response);
console.log(obj);
});
7.原生-post-携带参数
const xhr = new XMLHttpRequest();
// open 来指定 请求方式
xhr.open("post", "http://www.itcbc.com:3006/api/addbook");
const data = {
bookname: "1从入门到精通1",
author: "我自己",
publisher: "黑马出版社",
appkey: "wanshao1234",
};
// 把data 转成 a=b&c=d .... URLSearchParams
const usp = new URLSearchParams(data);
const query = usp.toString();
// 设置对应的 content-type
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(query); // 传递 a=b&c=d
xhr.addEventListener("load", function () {
console.log(this.response);
});
8.原生-post-携带参数-json
const xhr = new XMLHttpRequest();
xhr.open("post", "http://www.itcbc.com:3006/api/addbook");
// post 三种不同数据格式的参数
// 1 a=b&c=d 同时也需要指定 content-type 才行!!
// 2 对象格式 {a:"b",c:"d"} 同时也需要指定 content-type 才行!!
// 3 formdata 数据
const data = {
bookname: "2从入门到精通2",
author: "我自己",
publisher: "黑马出版社",
appkey: "wanshao1234",
};
// 设置对应的 content-type
xhr.setRequestHeader("Content-type", "application/json");
const str = JSON.stringify(data);
xhr.send(str); // 传递 a=b&c=d
xhr.addEventListener("load", function () {
console.log(this.response);
});
9.原生-post-携带参数-formdata
<body>
<input type="file" accept="image/*" />
<script>
const input = document.querySelector("input");
input.addEventListener("change", function () {
const file = this.files[0];
const formdata = new FormData();
formdata.append("avatar", file);
const xhr = new XMLHttpRequest();
xhr.open("post", "http://www.itcbc.com:3006/api/formdata");
// 不用设置 content-type
xhr.send(formdata);
xhr.addEventListener("load", function () {
console.log(this.response);
});
});
</script>
</body>
10.ajax代码的封装1
(1)type 可能是get 也可能是post
(2)data 3种(查询字符串 json formdata )
(3)希望封装的代码 什么样式
ajax({url,type,data,success})
{
url: 'http://www.itcbc.com:3006/api/getbooks',
type: 'post',
data: "appkey=wanshao1234",
success(result) {
console.log(result);
}
(4)jq中 也是封装过 ajax代码
// jq中 也是封装过 ajax代码
$.ajax({
url: "http://www.itcbc.com:3006/api/getbooks",
type: "post",
data: "appkey=wanshao1234",
success(result) {
console.log(result);
},
});
11.ajax代码的封装2
(1)ajax 是一个函数(正解) 还是 一个对象
(2)它接受一个 参数 格式 什么格式(对象)
(3)需要在ajax函数中 写完 整个原生ajax 发送请求的代码
const option = {
url: "http://www.itcbc.com:3006/api/getbooks",
type: "get",
data: "appkey=wanshao1234",
success(result) {
// result 等于 要等于响应的数据 = 对象格式
console.log(result);
},
};
ajax(option);
function ajax(config) {
const xhr = new XMLHttpRequest();
xhr.open(config.type, config.url + "?" + config.data);
xhr.send();
xhr.addEventListener("load", function () {
// 响应的数据 this.response
// console.log(this.response);
const obj = JSON.parse(this.response);
config.success(obj);
});
}
12.ajax代码的封装.-get-不携带参数
(1)关键代码
// 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
const xhr = new XMLHttpRequest();
if (config.data) {
// 有传递参数
xhr.open(config.type, config.url + "?" + config.data);
} else {
xhr.open(config.type, config.url);
}
(2)完整代码
const option = {
url: "http://www.itcbc.com:3006/api/getbooks",
type: "get",
// data: 'appkey=wanshao1234',
success(result) {
console.log(result);
},
};
ajax(option);
ajax({
url: "http://www.itcbc.com:3006/api/getbooks",
type: "get",
data: "appkey=wanshao1234",
success(result) {
console.log(result);
},
});
function ajax(config) {
console.log(config.data);
// 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
const xhr = new XMLHttpRequest();
if (config.data) {
// 有传递参数
xhr.open(config.type, config.url + "?" + config.data);
} else {
xhr.open(config.type, config.url);
}
xhr.send();
xhr.addEventListener("load", function () {
const obj = JSON.parse(this.response);
config.success(obj);
});
}
13.ajax代码的封装.-get-不携带参数-优雅
(1)关键代码
// 用到解构+继承原理,有则用,无则默认data = ""
function ajax({ url, type, data = "", success }) {
// 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
const xhr = new XMLHttpRequest();
xhr.open(type, url + "?" + data);
// 如果 data没有值 url = http://www.itcbc.com?
// 如果 data有值 url = http://www.itcbc.com?appkey=wanshao1234
xhr.send();
xhr.addEventListener("load", function () {
const obj = JSON.parse(this.response);
success(obj);
});
}
(2)完整代码
const option = {
url: "http://www.itcbc.com:3006/api/getbooks",
type: "get",
// data: 'appkey=wanshao1234',
success(result) {
console.log(result);
},
};
ajax(option);
ajax({
url: "http://www.itcbc.com:3006/api/getbooks",
type: "get",
data: "appkey=wanshao1234",
success(result) {
console.log(result);
},
});
function ajax({ url, type, data = "", success }) {
// 封装的时候考虑到用户 (可能带参数 , 可能不带参数)
const xhr = new XMLHttpRequest();
xhr.open(type, url + "?" + data);
// 如果 data没有值 url = http://www.itcbc.com?
// 如果 data有值 url = http://www.itcbc.com?appkey=wanshao1234
xhr.send();
xhr.addEventListener("load", function () {
const obj = JSON.parse(this.response);
success(obj);
});
}
14.ajax代码-post
ajax({
url: "http://www.itcbc.com:3006/api/getbooks",
type: "get",
success(result) {
console.log(result);
},
});
ajax({
url: "http://www.itcbc.com:3006/api/getbooks",
type: "post",
success(result) {
console.log(result);
},
});
function ajax({ url, type, data = "", success }) {
const xhr = new XMLHttpRequest();
// 判断 请求类型
if (type === "get") {
// get请求的相关的代码
if (typeof data === "object") {
data = new URLSearchParams(data);
data = data.toString();
}
xhr.open(type, url + "?" + data);
xhr.send();
} else if (type === "post") {
// post请求的相关的代码
xhr.open(type, url);
xhr.send();
}
xhr.addEventListener("load", function () {
const obj = JSON.parse(this.response);
success(obj);
});
}
15.ajax代码-post-data传参
(1)判断当前data的数据类型
①字符串类型
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(data); // 传递 a=b&c=d
②对象类型
xhr.setRequestHeader("Content-type","application/json");
const str =JSON.stringify(data);
xhr.send(str); // 传递 a=b&c=d
③formdata
xhr.send(formdata);
(2)完整代码
①判读类型:get/post
②判断data数据类型
③执行对应的请求代码
const input = document.querySelector("input");
input.addEventListener("change", function () {
const file = this.files[0];
const formdata = new FormData();
formdata.append("avatar", file);
ajax({
url: "http://www.itcbc.com:3006/api/formdata",
type: "post",
data: formdata,
success(result) {
console.log(result);
},
});
});
function ajax({ url, type, data = "", success }) {
const xhr = new XMLHttpRequest();
// 判断 请求类型
if (type === "get") {
// get请求的相关的代码
if (typeof data === "object") {
data = new URLSearchParams(data).toString();
}
xhr.open(type, url + "?" + data);
xhr.send();
} else if (type === "post") {
// post请求的相关的代码
xhr.open(type, url);
// 判断是不是字符串
if (typeof data === "string") {
xhr.setRequestHeader(
"Content-type",
"application/x-www-form-urlencoded"
);
xhr.send(data);
} else if (typeof data === "object") {
// 判断是不是对象
// 判断是不是 FormData 实例
if (data instanceof FormData) {
// 是 FormData 实例
xhr.send(data);
} else {
// 普通的对象
xhr.setRequestHeader("Content-type", "application/json");
const str = JSON.stringify(data);
xhr.send(str); // 传递 a=b&c=d
}
}
}
xhr.addEventListener("load", function () {
const obj = JSON.parse(this.response);
success(obj);
});
}
四、防抖和节流
1.防抖(debounce)指的是:频繁触发某个操作时,只执行最后一次
2.防抖应用场景:
(1)搜索框只在输入完后,才执行查询的请求。 (2)好处:这样可以有效减少请求的次数,节省网络资源。
(3)原理:
1)用在输入框中 实现 不用用户按下回车键 就发送请求
2)技术原理
①应用新的一次输入来清除上一次的延时器
②同时开启一个新的延时器
3.防抖核心代码
clearTimeout(timeid);
// 开启了一个延时器 里面代码 1s后会执行
timeid = setTimeout(function () {
const value = input.value.trim();
const queryStr = `?bookname=${value}`;
getData(queryStr);
}, 1000);
4.防抖完整代码
getData();
// change事件 输入框的值发生改变-输入框失去焦点 才触发
// input 事件
// 定义一个 演示器 id
let timeid; // 钻 石 城 堡
const input = document.querySelector("input");
input.addEventListener("input", function (event) {
clearTimeout(timeid);
// 开启了一个延时器 里面代码 1s后会执行
timeid = setTimeout(function () {
const value = input.value.trim();
const queryStr = `?bookname=${value}`;
getData(queryStr);
}, 1000);
});
function getData(query = "") {
axios({
method: "get",
url: "http://www.itcbc.com:3006/api/getbooks" + query,
// params:{},
}).then((result) => {
console.log(result);
const arr = result.data.data;
render(arr);
});
}
function render(arr) {
let html = arr
.map(
(value) => `
<tr>
<td>${value.id}</td>
<td>${value.bookname}</td>
<td>${value.author}</td>
<td>${value.publisher}</td>
</tr>
`
)
.join("");
document.querySelector("tbody").innerHTML = html;
}
5.节流(throttle)指的是:单位时间内,频繁触发同一个操作,只会触发 1 次。
6.节流应用场景:
射击游戏中,单位时间内只能发射一颗子弹;上一次的业务没有结束的话 不允许开启下一次业务使用场景 移动端分页 - 倒计时按钮 等等
let isLoadding = false; // 有没有请求在发送当中
// 点击按钮的时候先判断 isLoadding true还是false
// true 请求在发送中 return
// false 没有请求
// 先设置 isLoadding true
// 发送请求出去
// 请求回来了 设置 isLoadding = false
document.querySelector("button").addEventListener("click", function () {
if (isLoadding) {
return;
}
isLoadding = true;
// 发送请求的时候 禁用按钮
// this.disabled=true;
getData();
});
function getData(query = "") {
console.log("请求发送出去");
axios({
method: "get",
url: "http://www.itcbc.com:3006/api/getbooks" + query,
// params:{},
}).then((result) => {
console.log("数据回来了");
// document.querySelector('button').disabled=false
isLoadding = false;
});
}