Ajax 第四天
请求-响应报文
本质:客户端与服务器通信的过程是基于请求和响应的。
1.请求报文:规定了客户端以什么格式把数据发送给服务器
2.响应报文:规定了服务器以什么格式把数据响应给客户端
作用:方便我们做代码的调试
请求报文-格式
1.请求报文:请求行,请求头,空行和请求体4个部分组成
2.响应报文:状态栏,响应头部,空行和响应体4个部分组成
URL参数
本质:常用的5种请求方式,都可以在URL后面携带请求参数
缺点:敏感信息会直接暴露在地址栏
写法:常用的请求参数有两种写法(第二种先了解)
<script>
//写法1 get(URL)
axios.get("http://www.itcbc.com:3006/api/getbooks?appkey=HZD123")
.then((result)=>{
console.log(result);
})
//写法2 get(URL,{params:参数})
axios.get("http://www.itcbc.com:3006/api/getbooks",{params:{appkey:`HZD123`}})
.then((result)=>{
console.log(result);
})
</script>
请求体
本质:除了GET请求以外,其他4种常用的请求方式,都可以设置请求体
作用:请求体大小没有限制,所以可以提交大量的数据
写法:
<script>
// 写法1 axios.post(url,参数(对象))
axios.post("http://www.itcbc.com:3006/api/addbook?appkey=HZD123",{bookname:`黄某`,appkey:`XXX`})
.then((result)=>{
console.log(result);
})
// 写法2 axios.post(url,参数(字符串))
axios.post("http://www.itcbc.com:3006/api/addbook?appkey=HZD123",`bookname=黄某&appkey=XXX`)
.then((result)=>{
console.log(result);
})
// 写法3
axios.post(`http://www.itcbc.com:3006/api/formdata`
,formdata)
.then((result)=>{
console.log(result);
})
</script>
注意:请求的时候,设置了不同格式的请求体,需要一个对应的请求头
http响应状态码
本质:http响应状态码由三位数字组成,用来标识响应成功与否的状态
作用:客户端浏览器根据响应状态码,即可判断这次http请求是否成功
常见的http响应状态码
与业务状态码区分
本质:所处的位置,表示的结果,通用性不同
1.所处的位置不同
在响应头的状态行中所包含的状态码,或者请求列表中的Status
业务状态码在响应体的数据中所包含的状态码,如案例中的code
2.表示的结果不同
响应状态码只能表示这次请求是否成功
业务状态码·表示这次业务处理是否成功
3.通用性不同
响应状态码是由http协议规定的,具有通用性。每个不同的状态码都有标准含义
业务状态码是后端程序员自己定义的,不具有通用性(如聚合,天行,百度等API的接口)
XMLHttpRequest
本质:是浏览器内置的一个构造函数
作用:
1.基于new出来的XHR实例对象,可以发起Ajax的请求。
2.axios中的axios.get() .post()等方法都是基于XHR来的,XHR是原生(底层)代码
XHR发起GET请求
实现步骤
<script>
const xhr = new XMLHttpRequest
xhr.open(`get`,`http://www.itcbc.com:3006/api/getbooks`)
xhr.send()
xhr.addEventListener(`load`,function(){
console.log(this.response); //默认 是字符串的格式
const obj = JSON.parse(this.response)// 反序列化
console.log(obj.data);
})
</script>
请求时携带URL参数
get方法携带参数
<script>
const xhr = new XMLHttpRequest
xhr.open(`get`,`http://www.itcbc.com:3006/api/getbooks?appkey=HZD123`)
xhr.send()
xhr.addEventListener(`load`,function(){
console.log(this.response);
const obj = JSON.parse(this.response)
const arr = obj.data
console.log(arr);
const html = arr.map((value)=>`<li>${value.bookname}</li>`).join(``)
document.querySelector(`ul`).innerHTML=html
})
</script>
post提交请求体数据时
1.调用xhr.setRequestHeader()函数,指定请求体编码格式
2.当请求体格式不同时,需要指定Content-Type的请求头
对象格式
<script>
const xhr = new XMLHttpRequest()
xhr.open(`post`, `http://www.itcbc.com:3006/api/addbook`)
const data = {
bookname: '2从入门到精通2',
author: '我自己',
publisher: '黑马出版社',
appkey:`HZD123`
}
// 对象格式的参数 也要指定 conten-type
xhr.setRequestHeader(`Content-type`,`application/json`)
const str = JSON.stringify(data)
xhr.send(str) //?
xhr.addEventListener(`load`,function(){
console.log(this.response);
})
</script>
字符串格式
<script>
const xhr = new XMLHttpRequest()
xhr.open(`post`,`http://www.itcbc.com:3006/api/addbook`)
//要传递的参数
const data = {
bookname:`黄某奇妙冒险`,
author:`黄某`,
publisher:`黄某之家`,
appkey:`HZD123`
}
//把data数据 转换 a=1&b=2
const usp = new URLSearchParams(data)
const query = usp.toString()
console.log(query);
// a=1&b=2 需要指定 content-type 规定
xhr.setRequestHeader(`Content-type`,`application/x-www-form-urlencoded`)
// post请求的参数 只能写在 send()
xhr.send(query)
xhr.addEventListener(`load`,function(){
console.log(this.response);
})
</script>
FormData形式
<script>
const inp = document.querySelector(`input`)
const img = document.querySelector(`img`)
inp.addEventListener(`change`, function () {
const file = this.files[0]
const src = URL.createObjectURL(file)
img.src = src
const formdata = new FormData()
formdata.append(`avatar`,file)
const xhr = new XMLHttpRequest()
xhr.open(`post`,`http://www.itcbc.com:3006/api/formdata`)
xhr.send(formdata)
xhr.addEventListener(`load`,function(){
console.log(this.response);
})
})
</script>
自封装Ajax
1.根据JQ的Ajax出发,封装属于自己的Ajxa
<script>
// JQ的代码也是通过封装的 我们跟着这个代码思路自封装
$.ajax({
url: `http://www.itcbc.com:3006/api/getbooks`,
type: `get`,
data: `appkey=HZD123`,
success(result) {
console.log(result);
}
})
const option = {
url: `http://www.itcbc.com:3006/api/getbooks`,
type: `get`,
data: `appkey=HZD123`,
success(result) {
console.log(result);
}
}
// 我们自己封装一个Ajax函数 来实现ajax上传功能
ajax(option) // 这是一个函数 调用option里面的属性 实现上传
</script>
2.实现第一步功能 GET 方式 不携带参数
<script>
function ajax(config) {
const xhr = new XMLHttpRequest()
// 因为 元素 Ajxa get 请求 携带参数 只能拼接在 URL 后
xhr.open(config.type, config.url + `?` + config.data)
xhr.send()
xhr.addEventListener(`load`, function () {
//this.response = 上传的返回值转对象后 = option.success(result)
const obj = JSON.parse(this.response)
config.success(obj)
})
}
</script>
3.当GET方式 携带参数
<script>
function ajax({type,url,data=``,success}) {
const xhr = new XMLHttpRequest()
xhr.open(type, url + `?` + data)
xhr.send()
xhr.addEventListener(`load`, function () {
const obj = JSON.parse(this.response)
success(obj)
})
}
</script>
4.当GET方式中 data是不同类型时
<script>
function ajax({ url, type, data = ``, success }) {
const xhr = new XMLHttpRequest()
if (typeof data === `object`) {
data = (new URLSearchParams(data)).toString()
}
xhr.open(type, url + `?` + data)
xhr.send()
xhr.addEventListener(`load`, function () {
const obj = JSON.parse(this.response)
success(obj)
})
}
</script>
5.封装POST 方式
判断当前data数据类型:字符串、对象、FormData(之前内容)
<script>
function ajax({ url, type, data = ``, success }) {
const xhr = new XMLHttpRequest()
// get请求类型
if (type === `get`) {
if (typeof data === `object`) {
data = (new URLSearchParams(data)).toString()
}
xhr.open(type, url + `?` + data)
xhr.send()
// post请求类型
} else if (type === `post`) {
xhr.open(type, url)
// 判断是不是字符串
if (typeof data === `string`) {
xhr.setRequestHeader(`Content-type`, `application/x-www-form-urlencoded`)
xhr.send(data)
// 判断是不是对象(普通对象和FormData)
} else if (typeof data === `object`) {
// 判断 实例和构造函数的关系 实例 instanceof 构造函数
if (data instanceof FormData) {
xhr.send(data)
} else {
xhr.setRequestHeader(`Content-type`, `application/json`)
const str = JSON.stringify(data)
xhr.send(str)
}
}
}
</script>
总结:
1.通过今天所学的底层原生Ajax 代码 来封装一个 自己的Ajax上传函数 用JQ的Ajax做参考
2.参照JQ的ajxa代码格式 运用底层的原生Ajax 进行封装使用
3.有传参和不传参两种情况 用默认值+解构思路 进一步优化代码
4.最后把形参.属性名 优化 解构{属性名,data=``(默认值)}
5.data可以是没有参数 可以是字符串 还可以是对象
6.type of 判断是否为对象 运用URLsearcParams/ .toString()转换数据
7.post请求方式 与get不同 所以用if区分 get一部分 post 一部分
8.判断当前data数据类型:字符串、对象、FormData 分别放入相应判断函数内
9.判断字符串类型: typeof 判断实例对应构造函数: 实例 instanceof 构造函数
防抖-节流
节流
本质:指的是单位时间内,频繁触发同一个操作,只会触发1次
<script>
let isLoadding = false;
document.querySelector('button').addEventListener('click', function () {
if (isLoadding) {
return;
}
isLoadding = true;
getData();
});
function getData(query = '') {
console.log('请求发送出去');
axios({
method: 'get',
url: 'http://www.itcbc.com:3006/api/getbooks' + query,
}).then((result) => {
console.log('数据回来了');
isLoadding = false;
});
}
</script>
应用场景
防抖
本质:指的是频繁触发某一个操作,只能执行最后一次
<script>
let timeId
keyword.addEventListener(`input`, function (e) {
clearTimeout(timeId)
timeId = setTimeout(function () {
let value = keyword.value.trim()
let valuePush = `?bookname=${value}`
getData(valuePush)
}, 1000)
})
</script>
应用场景