一、XMLHttpRequest
01-什么是 XMLHttpRequest
// 是浏览器内置的一个构造函数
// 作用:基于 new 出来的 XMLHttpRequest 实例对象,可以发起 Ajax 的请求。
// axios 中的 axios.get()、axios.post()、axios() 方法,都是基于 XMLHttpRequest(简称:XHR) 封装出来的!
// 我们完全可以能否不用 axios 封装的 Ajax 函数,直接基于 XMLHttpRequest 发起 Ajax 请求
02-使用 XMLHttpRequest 发起 GET 请求
- 主要的 4 个实现步骤:
- 1.创建 xhr 对象
- 2.调用 xhr.open() 函数
- 3.调用 xhr.send() 函数
- 4.监听 load 事件
03-使用XMLHttpRequest发起无参请求
<body>
<button>点我啊</button>
<script>
let btn = document.querySelector('button')
btn.addEventListener('click', function() {
// 1.创建一个异步对象
let xhr = new XMLHttpRequest()
// 2.发起请求:设置正确的请求报文
// 2.1 报文行:设置请求方式和请求url,调用open方法可以设置请求行
xhr.open('get', 'http://www.itcbc.com:3006/api/getbooks')
// 2.2 报文头:get方式不用设置报文头,因为它的参数是进行url拼接,所以不用设置编码格式
// 2.3 报文体:设置本次请求传递给服务器的参数,同时发起请求,get方式的参数在url中拼接,所以不用在这个位置传递参数,调用send可以发起请求
xhr.send()
// 3.接收响应
// 由于是一个异步请求,所以我们不知道什么时候响应,那么当数据响应回客户端可以使用的时候,就会触发load事件,返回值就在xhr的response属性中
xhr.addEventListener('load', function() {
console.log(xhr.response, typeof xhr.response)
console.log(JSON.parse(xhr.response), typeof JSON.parse(xhr.response))
})
})
</script>
</body>
04-使用XMLHttpRequest发起带参请求
// 2.发起请求:设置正确的请求报文
// 2.1 报文行:设置请求方式和请求url,调用open方法可以设置请求行
// 如果有参数,在原生代码中,需要在url后面拼接
xhr.open(
'get',
'http://www.itcbc.com:3006/api/getbooks?bookname=' + value
)
05-使用XMLHttpRequest发起post请求
- 提交请求体数据,需指定Content-Type头
- 当需要提交请求体数据时,需要在 xhr.open() 之后,调用 xhr.setRequestHeader() 函数,指定请求体的编码格式
HTML解构
<form class="card-body bg-light" id="addForm">
<!-- 书名 -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">书名</span>
</div>
<input
type="text"
class="form-control"
placeholder="请输入图书名称"
name="bookname"
/>
</div>
<!-- 作者 -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">作者</span>
</div>
<input
type="text"
class="form-control"
placeholder="请输入作者名字"
name="author"
/>
</div>
<!-- 出版社 -->
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">出版社</span>
</div>
<input
type="text"
class="form-control"
placeholder="请输入出版社名称"
name="publisher"
/>
</div>
<input type="button" value="添加" class="btn btn-dark btnadd" />
</form>
JS代码
<script>
let btnadd = document.querySelector('.btnadd')
// 书名
let bookname = document.querySelector('[name="bookname"]')
// 作者
let author = document.querySelector('[name="author"]')
// 出版商
let publisher = document.querySelector('[name="publisher"]')
btnadd.addEventListener('click', function() {
// 1.创建一个异步对象
let xhr = new XMLHttpRequest()
// 2.发起请求
// 2.1 设置请求行:open(方式,地址)
xhr.open('post', 'http://www.itcbc.com:3006/api/addbook')
// 2.2 设置请求头:post方式需要设置请求头,默认情况下编码格式应该设置为:application/x-www-form-urlencoded
// 通过 setRequestHeader 方法可以设置请求头
// Content-Type:用来设置参数的编码格式的
xhr.setRequestHeader(
'Content-Type',
'application/x-www-form-urlencoded'
)
// 2.3 设置请求体,通过send方法可以设置
// post方式的参数需要在请求体中传递,默认的格式为:key=value&key=value
xhr.send(
`bookname=${bookname.value}&author=${author.value}&publisher=${publisher.value}`
)
// 3.接收响应
xhr.addEventListener('load', function() {
console.log(xhr.response)
})
})
</script>
06-请求体格式 和 对应的Content-Type值
- 为了方便服务器接收数据,当提交请求体时,需要指定一个叫做Content-Type的请求头
btnadd.addEventListener('click', function() {
// 1.创建一个异步对象
let xhr = new XMLHttpRequest()
// 2.发起请求
// 2.1 设置请求行:open(方式,地址)
xhr.open('post', `http://www.itcbc.com:3006/api/addbook`)
// 2.2 设置请求头:post方式需要设置请求头,默认情况下编码格式应该设置为:application/x-www-form-urlencoded
// 通过 setRequestHeader 方法可以设置请求头
// Content-Type:用来设置参数的编码格式的
// xhr.setRequestHeader(
// 'Content-Type',
// 'application/x-www-form-urlencoded'
// )
// 2.3 设置请求体,通过send方法可以设置
// post方式的参数需要在请求体中传递,默认的格式为:key=value&key=value
// xhr.send(
// `bookname=${bookname.value}&author=${author.value}&publisher=${publisher.value}`
// )
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(
JSON.stringify({
bookname: bookname.value,
author: author.value,
publisher: publisher.value
})
)
// 3.接收响应
xhr.addEventListener('load', function() {
console.log(xhr.response)
})
})
二、数据交换格式
01-什么是数据交换格式
- 数据交换格式,就是服务器端与客户端之间数据传输的格式。
- 两种数据交换格式:XML(很少用) JSON(主流)
02-什么是 JSON
JSON(全称:JavaScript Object Notation)是一种数据交换格式,它本质上是用字符串的方式来表示对象或数组类型的数据。例如:
03-JSON 数据
- 用字符串的方式来表示的对象或数组类型的数据,叫做 JSON 数据。
- JSON 数据的格式有两种:1.对象格式 2.数组格式
04-JSON 的语法要求
使用 JSON 定义 JSON 格式的数据时,要遵守以下的 6 条规则:
1. 属性名必须使用双引号包裹
2. 字符串类型的值必须使用双引号包裹
3. JSON 中不允许使用单引号表示字符串
4. JSON 中不能写注释
5. JSON 的最外层必须是对象或数组格式(其他类型也可以,但多数是对象或数组格式)
6. 不能使用 undefined 或函数作为 JSON 的值
05-对象格式的 JSON 数据
对象格式的 JSON 数据,最外层使用 { } 进行包裹,内部的数据为 "key": "value" 的键值对结构。其中:
1. key 必须使用英文的双引号进行包裹
2. value 的值只能是字符串、数字、布尔值、null、数组、对象类型(可选类型只有这 6 种)
06-数组格式的 JSON 数据
数组格式的 JSON 数据,最外层使用 [ ] 进行包裹,内部的每一项数据之间使用英文的 , 分隔。其中:
每一项的值类型只能是字符串、数字、布尔值、null、数组、对象这 6 种类型之一。
07-把 JSON 数据转换为 JS 数据
调用浏览器内置的 JSON.parse() 函数,可以把 JSON 格式的字符串转换为 JS 数据,例如:
08-把 JS 数据转换为 JSON 数据
调用浏览器内置的 JSON.stringify() 函数,可以把 JS 数据转换为 JSON 格式的字符串,例如:
09-序列化和反序列化
- 把真实数据转换为字符串的过程,叫做序列化
- 把字符串转换为真实数据的过程,叫做反序列化
10-把 XMLHttpRequest 请求到的 JSON 数据反序列化为 JS 对象
在 xhr 对象的 load 事件中,通过 xhr.response 访问到的是 JSON 格式的字符串数据。可以调用 JSON.parse() 函数将 xhr.response 转化为 JS 对象。示例代码如下:
三、封装自己的 Ajax 函数
定义 itheima 函数的参数选项
函数是自定义的 Ajax 函数,它接收一个配置对象作为参数。配置对象中包含如下 5 个参数选项:
| 参数选项 | 说明 |
|---|---|
| method | 请求的类型(GET 或 POST) |
| url | 请求的 URL 地址 |
| params | URL 末尾拼接的查询参数 |
| data | 请求体数据,有三种格式,分别是(FormData 格式、JSON 格式、普通字符串格式) |
| success | 请求成功之后的回调函数 |
实现步骤
1.简化参数及默认值处理
// 0.参数简化和处理
let method = option.method || 'get'
let url = option.url
if (!url) {
alert('一定要设置url')
return
}
let params = option.params
let data = option.data
2.创建一个异步对象
let xhr = new XMLHttpRequest()
3.处理get方式的params参数
- 是get请求,同时传递了params
- 将params对象转换为key=value的格式,拼接在url后面
if (params && method.toLowerCase() == 'get') {
url = url + '?' + exchange(params)
}
4.发起请求
5.接收响应
- 以回调函数的参数将后台响应数据返回
// 3.接收响应
xhr.addEventListener('load', function() {
// 通过回调函数的参数将后台响应数据返回
success(JSON.parse(xhr.response))
})
整体代码结构
HTML结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<script src="./js/myajax.js"></script>
</head>
<body>
<input type="text" />
<button class="all">查询所有数据</button>
<button class="search">查询指定名称的数据</button>
<script>
let input = document.querySelector('input')
let all = document.querySelector('.all')
let search = document.querySelector('.search')
all.addEventListener('click', function() {
// axios({
// method: 'get',
// url: 'http://www.itcbc.com:3006/api/getbooks',
// params: { bookname: '11' }
// // data:`bookname=111`
// })
axios({
method: 'post',
url: 'http://www.itcbc.com:3006/api/addbook',
// data: { bookname: '11', author: 'aaaa', publisher: 'adsfdsf' }
// data:`bookname=111`
data: `bookname=aaaa&author=author&publisher=publisher`,
success: function(res) {
console.log(res)
}
})
})
</script>
</body>
</html>
JS代码
function exchange(obj) {
let arr = []
for (let key in obj) {
console.log(key, obj[key])
arr.push(`${key}=${obj[key]}`)
}
return arr.join('&')
}
// 添加一个工具函数
// option:是一个配置对象
// method:请求方式
// url:请求地址
// params:是get请求方式的参数
// data:是post请求方式的参数
function axios(option) {
// 0.参数简化和处理
let method = option.method || 'get'
let url = option.url
if (!url) {
alert('一定要设置url')
return
}
let params = option.params
let data = option.data
let success = option.success
// 1.创建异步对象
let xhr = new XMLHttpRequest()
// 2.发请求
// 2.1 设置请求行
// 判断:传递了params,且请求方式是get,我们需要将params对象转成字符串拼接到url后面
if (params && method.toLowerCase() == 'get') {
url = url + '?' + exchange(params)
}
xhr.open(method, url)
// 2.2 设置请求头:只有post方式才需要进行请求头的设置
if (method.toLowerCase() == 'post') {
// 说明传递了key=value&key=value
if (typeof data == 'string') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send(data)
} else if (data instanceof FormData) {
// 传递了formdata,浏览器进行设置好请求头
xhr.send(data)
} else {
xhr.setRequestHeader('Content-Type', 'application/json')
// 将对象转换为字符串
xhr.send(JSON.stringify(data))
}
} else {
xhr.send()
}
// 3.接收响应
xhr.addEventListener('load', function() {
// 通过回调函数的参数将后台响应数据返回
success(JSON.parse(xhr.response))
})
}
同源策略 & 跨域(面试服务)
-
3.1 同源跨域是浏览器的安全策略
- 可以正常的向服务器发起数据请求
- 服务器也会正常的响应
- 但是浏览器会阻止数据的返回
-
3.2 同源:协议,域名(IP),端口都一样,则同源,但凡有一个不一样则跨域
- 浏览器认为与不同源的url交互不安全
-
3.3 解决跨域的三种常见方案
-
cors跨域:服务器端跨域
- 在服务器端进行设置的,前端不用任何的改变
app.use('/', (req, res, next) => { // * 允许所有源来发起跨域请求 res.setHeader('Access-Control-Allow-Origin', '*') res.setHeader('Access-Control-Allow-Credential', 'true') res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS') next() }) 复制代码 -
jsonp跨域:浏览器跨域
- 本质是利用了Scirpt标签的src天然跨域特性
- 通过Script获取的内容会默认以js语法来解析
- 在发起请求的时候,传递一个函数名称,服务器返回函数调用形式并拼接相应的数据
- jsonp与异步对象没有任何的关系,它不是一个异步请求,只能发get请求
-
4、防抖
- 4.1 是指多次触发,只执行最后一次
- 4.2 将业务处理代码放到延迟器中
- 4.3 每次触发事件之后,先清除之前的延迟器,再重新添加延迟器,实现重新计时
- 4.4 代码演示:
let tid = null
// input:内容改变就会触发
input.addEventListener('input', function() {
// 先清除之前所添加的延迟器
clearTimeout(tid)
tid = setTimeout(() => {
axios({
url: 'http://www.itcbc.com:3006/api/getbooks'
}).then(res => {
console.log(res)
})
}, 2000)
})
复制代码
5、节流
- 5.1 是指多次触发,只执行第一次
- 5.2 定义一个标识,如果满足条件才进行处理
- 5.3 在第一次操作之后,将标识进行重置,例如重置为false,再进行操作不再处理
- 5.4 本次操作完成了,将标识再重置为true
- 5.5 代码演示:
let flag = true // true表示 本次单击应该进行处理
button.addEventListener('click', function() {
if(!flag){ return}
flag = false
setTimeout(() => {
console.log(123)
flag = true
}, 2000)
})