【前端43_前后端交互】Ajax、网络请求、同步和异步请求、FormData 实现文件上传、监控上传速度和进度
Ajax 简单介绍
Ajax 即 “Asynchronous Javascript And XML”(异步 JavaScript 和 XML)
它是一项技术,提高了用户的体验,为什么这么说呢?
场景
举个栗子,如果我们做个登录的功能,当用户输入完姓名后,我需要去请求后台,校验一下数据库中是否重名,如果没有 ajax,那么只能通过跳转进行后端访问,这个体验太糟糕了。
我们想的是:能否不需要刷新页面就可以访问后台接口?所以 Ajax 应运而生。
实例:验证用户名输入
根据刚才的场景,我们来写一下代码。顺便简单介绍 Ajax
的使用
前端:
首先新建一个
XMLHttpRequest
对象1
let xhr = new XMLHttpRequest();
然后配置请求参数
xhr.open();
,其中true
是异步,false
是同步,后面会说到1
xhr.open("get", "/checkUserName", true); //true是异步,false是同步
接着接受返还值
1
2
3xhr.onload = function () {
let res = JSON.parse(xhr.responseText);
};发送服务器
1
xhr.send();
前端校验用户名的主要代码如下:
1 | document.querySelector(".inputStyle").onblur = function () { |
后端:
1 | router.get("/checkUserName", async (ctx) => { |
先感受一下 ajax
网络请求
GET
使用如下:
1 | let xhr = new XMLHttpRequest(); |
注意点
- get 通过
parmas
传参 - get 和 querystring 的问题,通过 url 传参
传参方式
如果 get
是这样携带参数的话
1 | // 这里传递了一个数字: 3 |
后台就需要这样去接收,我声明了一个叫 id
的变量(这个变量名字也可以随便取),它来接受前端传来的 3
1 | router.get("/getText/:id", (ctx) => { |
注意:要写这个冒号和名称,不然前端会报错 404
的
POST
前端发送数据是要声明编码格式,设置http
正文头格式
1 | // 发送数据时候需要设置http正文头格式; |
以下是个栗子 🌰
1 | document.querySelector("#btn").onclick = function () { |
后端接收,需要先引入 koa-body
框架,然后通过 ctx.request.body
来获取参数
1 | router.post("/postText", (ctx) => { |
前端也可以获得到后端返回的 头部信息
1 | let allRes = xhr.getAllResponseHeaders(); // 获取响应头,有些属性是获取不到的,可以查看 w3c 的文档 |
栗子如下:
1 | document.querySelector("#btn").onclick = function () { |
编码格式(自测笔记)
application/x-www-form-urlencoded
form
表单默认的编码格式如下,如果想设置其他值,在 form
标签上可以这样设置。
1 | enctype = "application/x-www-form-urlencoded"; |
传递数据的样子是这样的:
1 | let data = `username=王五&age=20`; |
multipart/form-data
如果是上传文件的话可以用
1 | xhr.setRequestHeader("Content-Type", "multipart/form-data"); //二进制编码 |
application/json
如果是 JSON
的话
1 | xhr.setRequestHeader("content-type", "application/json"); |
那么数据的样子就要是这个
1 | let data = JSON.stringify({ |
总结
- post 是密文传输,
- 他也可以通过 url 来传递参数,
- 但是这样传递就失去了密文传输的意义了,没有大小显示,
- 服务器可能会显示,如果没有限制的话,那就是无穷大了。
- 在 http 正文传参,需要(必须)设置编码格式
- get
- 明文传输
- 有大小显示
其他知识补充
- Koa 在 ctx.body 的时候会把对象自动帮我们
JSON.stringify()
Ajax 的同步和异步
实验
来个实验就很明了
实验:我在页面上放两个按钮,注意我点的顺序:我都是先点
按钮1
然后再点按钮2
,其中两个按钮的逻辑如下:
1 | let btns = document.querySelectorAll("button"); |
逻辑介绍完了,此时我在设置同步和异步
同步情况
同步:不建议,会卡进程的,我改成同步的效果如下:
可以看到输出的顺序,等按钮 1 的 Ajax 请求结束后才执行的 按钮 2
异步情况
异步的情况如下:
Ajax 默认设置的是异步,也就是你不写参数的话,默认是异步的(你可以自行测试)。
测试的时候可以用 3g
网,浏览器里能调整。
xhr.onload 和 onreadystatechange
原先的请求成功,可以有两种写法
其中onreadystatechange
的写法如下
1 | xhr.onreadystatechange = function () { |
onreadystatechange
:存有处理服务器响应的函数,每当 readyState
改变时,onreadystatechange
函数就会被执行。
readyState 状态信息
readyState
:存有服务器响应的状态信息。
- 0: 请求未初始化(代理被创建,但尚未调用 open() 方法)
- 1: 服务器连接已建立(
open
方法已经被调用) - 2: 请求已接收(
send
方法已经被调用,并且头部和状态已经可获得) - 3: 请求处理中(下载中,
responseText
属性已经包含部分数据) - 4: 请求已完成,且响应已就绪(下载操作已完成)
status 常用状态码
HTTP状态码 | 描述 |
100 | 继续。继续响应剩余部分,进行提交请求 |
200 | 成功 |
301 | 永久移动。请求资源永久移动到新位置 |
302 | 临时移动。请求资源零时移动到新位置 |
304 | 未修改。请求资源对比上次未被修改,响应中不包含资源内容 |
401 | 未授权,需要身份验证 |
403 | 禁止。请求被拒绝 |
404 | 未找到,服务器未找到需要资源 |
500 | 服务器内部错误。服务器遇到错误,无法完成请求 |
503 | 服务器不可用。临时服务过载,无法处理请求 |
如何返还并接收 xml
后台返还一个 xml
1 | router.get("/xml", (ctx) => { |
前端接收 xml
1 | document.querySelector("button").onclick = function () { |
如果后端没有声明返还的文件是 xml,也就是 ctx.set('content-type', 'text/xml')
这个,那么前端可以重新设置头
就是你觉得哎后端 返回来一堆东西优点像 xml
啊,但是后端它没设置,那么咱们前端也可以设置
1 | xhr.overrideMimeType("text/xml"); // 前端设置 content-type 类型 |
举个使用场景的栗子:
1 | document.querySelector("button").onclick = function () { |
利用 FormData 实现文件上传
简写上传
主要利用的也是 ajax
,这里引入了新的对象 new FormData()
概括流程:我们要把文件数据获取并
append
到FormData
这个对象中去,然后把formdata
发送到服务器中。
前端这边代码如下:
1 | document.querySelector("button").onclick = function () { |
后端接收注意要在后端这里允许上传文件
1 | app.use( |
路由如下:
1 | router.post("/upload", (ctx) => { |
后端处理文件
node
会帮我们把文件存储到临时地址,我们可以通过 fs
模块拿到文件,然后写到自己想要的位置
后端检测文件夹是否存在,并且转存文件到指定目录
1 | router.post("/upload", (ctx) => { |
前端 xhr.upload 上传钩子函数
大概有如下几个钩子(比较常用的)
1 | xhr.upload.onprogress = (event) => { |
onprogress
这个函数是在上传过程中不断循环被执行的,其中有事件因子 event
,里面会有上传中的信息
如果想要监控速度和进度的话,可以在上传的过程中计算出来
利用钩子函数计算下载速度和进度
思路就是求出一段时间的下载量和一段时间,然后做除法
1 | let oldDataSize; |
代码 git 地址
在高级-前后端交互
中
1 | https://gitee.com/lovely_ruby/DailyPractice/tree/main |