1.前后端交互
其实就是一个前后端通讯, 是我们在开发中, 必不可少的一个技能
目前我们用到的技术就是 ajax
流程为 在前端开发中, 在某一个时刻(页面首次打开渲染的时候, 或者点击下一页需要新的数据的时候)
此时通过 ajax 向后端(服务端)发送一个请求, 拿到 所谓的数据
发送请求需要传一些参数(就是告诉后端你要什么东西), 如果你不知道, 那么问你的组长要一个 '接口文档'
2.实现一个 ajax 请求
// 1. 创建一个 ajax 对象
const xhr = new XMLHttpRequest()
// 2. 配置 ajax 对象
// xhr.open('请求的方式(不区分大小写)', '请求的地址', '一个布尔值')
xhr.open('GET', 'http://localhost:8888/test/first', true)
// 3. 发送请求
xhr.send()
// 4. 接收响应
xhr.onload = function () {
// console.log('现在后端已经给我们返回了 我们想要的数据了')
console.log(xhr.responseText) // 哇塞, 你已经成功使用 ajax 发送给我了一个请求, 这是我给你的回应, 我是一个字符串类型 ^_^ !
}
3.ajax 的异步问题
ajax 是否异步为 第二步配置的第三个参数决定的, 也就是那个布尔值
默认为 true 代表的是开启异步, 如果传递的是 false 代表关闭异步开启同步
同步和异步的差别
-
- 创建一个 ajax 对象 (同步代码)
-
- 配置对象 (同步代码, 但是第三个参数决定了 下一步是否为异步)
-
- 发送请求 (根据上一步的配置, 才能看出是否为异步)
-
- 接受响应 (同步代码)
如果传递的是 true 或者没有传递, 那么为异步, 此时的运行流程
-
- 创建一个对象
-
- 配置对象
-
- 发送请求
-
- 接收响应
-
- 响应完成了
如果传递的是 false, 那么为同步, 此时的运行流程
-
- 创建一个对象
-
- 配置对象
-
- 发送一个请求, 等待请求完成后, 开始执行后边的代码
-
- 接收响应 (前边三步已经把这个请求完全的运行结束了, 所以此时不可能再触发这个函数了)
如果传递的是 false, 那么为同步, 此时的运行流程
-
- 创建一个对象
-
- 配置对象
-
- 接收响应, 等到请求完成的时候, 会触发
-
- 发送一个请求, 等待请求完成后, 开始执行后边的代码
如果传递是异步, 可以按照 1234的流程书写(1243也可以)
如果传递的是同步, 必须按照 1243 的流程书写
所以在开发的时候, 为了方便起见, 一般都会书写为 1243
// 1. 创建一个 ajax 对象
const xhr = new XMLHttpRequest()
// 2. 配置 ajax 对象
xhr.open('GET', 'http://localhost:8888/test/first', false)
// 4. 接收响应
xhr.onload = function () {
// console.log('现在后端已经给我们返回了 我们想要的数据了')
console.log(xhr.responseText) // 哇塞, 你已经成功使用 ajax 发送给我了一个请求, 这是我给你的回应, 我是一个字符串类型 ^_^ !
}
// 3. 发送请求
xhr.send()
4.http 传输协议
还有一个协议 https, 相对于 http 安全一点点
根据传输协议规定, 必须是由前端向后端发送请求, 发送请求的时候如果要携带一些参数, 必须是字符串格式
-
- 建立连接
- 浏览器和服务端 建立一个连接
-
- 发送请求
- 要求前端必须以 '请求报文' 的形式发送;
- 请求报文 由 浏览器进行组装, 我们只需要提供对应的信息即可;
- 比如说: 请求的方式, 请求的地址, 请求需要的参数
- 发送请求
-
- 接收响应
- 要求后端必须以 '响应报文' 的形式返回;
- 响应报文内有一个东西叫做响应状态码;
- 接收响应
-
- 断开连接
- 浏览器和服务端的连接断开
- 断开连接
响应状态码
- 100~199 表明连接还在继续
- 200~299 表明连接各种成功 但现在只会返回一个 200
- 300~399 表明请求重定向
- 400~499 表明请求失败 但现在只会看到一些 403 404 401 400 一般4开头是前端的问题
- 500~599 表明服务端出错 跟前端无关, 是后端的问题
5.ajax 的状态码
通过一个数字, 表明 ajax 当前运行到那一步了
- 0: ajax 创建成功
- 1: 当前 ajax 配置成功
- 2: 当前 ajax 发送成功
- 3: 当前 浏览器 正在解析服务端返回给我们的内容
- 如果返回的内容少, 这一步基本能接受完
- 如果返回的内容多, 这一步接收的是不完整的
- 4: 表明 浏览器 已经把服务端返回的内容 全都解析完毕了~
// 1. 创建一个 ajax 对象
const xhr = new XMLHttpRequest()
// console.log(xhr.readyState) // 0
// 2. 配置 ajax 对象
xhr.open('GET', 'http://localhost:8888/test/first')
// console.log(xhr.readyState) // 1
// 4. 配置接收响应的函数
// xhr.onload = function () {
// console.log(xhr.responseText)
// }
// 3. 发送请求
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log('当前浏览器已经完全解析完毕 返回的数据', xhr.responseText)
}
}
// xhr.onreadystatechange = function () {
// if (xhr.readyState === 2) {
// console.log('当前 请求 发送成功', xhr.responseText)
// } else if (xhr.readyState === 3) {
// console.log('当前浏览器正在解析返回的数据, 可能没完成', xhr.responseText)
// } else if (xhr.readyState === 4) {
// console.log('当前浏览器已经完全解析完毕 返回的数据', xhr.responseText)
// }
// }
6.请求方式的区别
- get 偏向于获取的语义 (商品列表数据, 用户详情, 商品详情)
- elete 偏向于获取的语义 (删除某一个内容)
- post 偏向于修改的语义 (修改用户名, 修改密码)
- put 偏向于修改的语义 (修改库存, 修改收藏数量)
- 等等..... 现在 市面公司中常用的方式只有两个, get/post
请求方式不同, 会导致传参的方式不同, 除此之外对我们前端来说没有区别
- get: 直接将需要传递参数拼接在路径后即可, 注意使用 ? 间隔
http://localhost:8888/test/first?key=valuehttp://localhost:8888/test/first?key=value&key2=value2
-
post: 也是需要传递字符串, 只不过不在放在 地址路径后, 而是放在 请求体内书写(其实就是 xhr.send())
- 在传参的时候还需要配置一个请求头中的属性 content-type
- content-type 赋值的时候, 还要区分我们传递的是普通字符串, 还是 json 格式的字符串
- 普通字符串: xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
- json字符串: xhr.setRequestHeader('content-type', 'application/json')
7.测试请求
//测试请求2
// 1. 创建一个 ajax 对象
const xhr = new XMLHttpRequest()
// 2. 配置 ajax 对象 xhr.open('请求方式', '请求地址')
xhr.open('GET', 'http://localhost:8888/test/second')
// 4. 配置接收响应的函数
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
console.log(res)
}
// 3. 发送请求
xhr.send()
//测试请求3
//1. 创建一个 ajax 对象
const xhr = new XMLHttpRequest()
// 2. 配置 ajax 对象 xhr.open('请求方式', '请求地址')
xhr.open('GET', 'http://localhost:8888/test/third?name=zhangsan&age=18')
// 4. 配置接收响应的函数
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
console.log(res)
}
// 3. 发送请求
xhr.send()
// 测试请求4
/**
* application/x-www-form-urlencoded 这是 post 格式的传参是需要给 content-type 配置的属性值
* 这样传递表明需要的是 普通字符串
*
* 如果是 json 格式的字符串, 需要传递为 application/json
*/
const xhr = new XMLHttpRequest()
// 2. 配置 ajax 对象 xhr.open('请求方式', '请求地址')
xhr.open('POST', 'http://localhost:8888/test/fourth')
// 4. 配置接收响应的函数
xhr.onload = function () {
const res = JSON.parse(xhr.responseText)
console.log(res)
}
// 3.1 post 请求传参时需要配置 content-type(请求头内的属性)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
// 3.2 发送请求
xhr.send('name=张三&age=18')
8.封装 ajax
- 参数:
-
- 请求的方式: 选填, 默认值为 GET; 形参名: type
-
- 请求的地址: 必填; 形参名: url
-
- 请求为同步还是异步: 选填, 默认值为 true; 形参名: async
-
- 请求需要携带参数: 选填, 默认为 ''; 形参名: data
-
- 返回值:
- 需要返回一个 promise 对象, 后续可以通过 .then 或者 async/await 去使用
// function myAjax(type = 'GET', url, async = true, data = '') {}
// myAjax('POST', 'http:xxx', false, 'name=zhangsan')
// myAjax('http:xxx', false, 'name=zhangsan')
// function myAjax(url, type = 'GET', async = true, data = '') { }
// myAjax('http:xxx', 'POST', false)
function myAjax(options) { }
myAjax({
url: 'http:xxx',
async: false,
data: 'name=zhangsan'
})
function myAjax(options) {
// 1. 验证 参数中的 url 必传
if (options.url === undefined) throw new Error('参数中缺少必传项 url') // 返回一个错误
// 1.1 参数格式验证, 拿请求方式举例: type 只接受 undefined 或者 string 两种类型
if (!(options.type === undefined || typeof(options.type) === 'string')) throw new Error('参数中 type 的类型必须为 string')
// 1.2 补全剩余参数的格式校验
// 2. 封装默认值
const _options = {
url: options.url,
type: options.type || 'GET',
data: options.data || '',
// 空值检测符, 该符号的特点 只会在 左侧的值为空值的时候返回右侧, 比如左侧为: null, undefined
async: options.async ?? true
}
// 请求的参数还没处理, 后续需要继续完善
const xhr = new XMLHttpRequest()
xhr.open(_options.type, _options.url, _options.async)
xhr.onload = function () {
console.log(xhr.responseText)
}
xhr.send()
}
myAjax({
url: 'http://localhost:8888/test/first',
})