主题
Axios 概述与axios 的安装使用(Day19 1/3)
本页对应 Day19-Fetch&Axios,共 6 段视频,约 1 小时 36 分。
学习目标
- 能够对比自定义 Promise 的 class 版与 function 版,说明实例方法、静态方法的添加位置差异,并定位状态、结果和回调队列三个属性。
- 能够用 REST API 风格说明 GET、POST、PUT、PATCH、DELETE 对同一资源路径的增删改查语义,并区分 PUT 与 PATCH 的修改范围。
- 能够全局安装并启动 json-server,指定数据文件、端口和 host,并通过浏览器验证接口返回的 JSON 数据。
- 能够定位并修改 hosts 文件,为 127.0.0.1 配置自定义域名别名,并说明 hosts 与 DNS 的解析先后关系。
- 能够使用 API 测试工具创建并发送 GET、POST、DELETE、PUT/PATCH 请求,检查请求体、响应状态、响应头和响应数据,完成 json-server 数据的增删改查验证。
- 能够概述 Axios 的安装使用、基本请求写法、常用请求配置项和响应结构,并能发起基本请求获取后端数据。
知识点
一、class 版自定义 Promise 回顾
为什么需要: 手写 Promise 不是为了替代内置 Promise,而是为了把“状态改变、回调注册、异步结果返回”这条链路真正想清楚。课堂反复强调“你传给我、我再传给你”,本质就是执行器函数、then 回调与状态修改之间的来回调用。
怎么想: 先看整体结构:实例方法有 then、catch,加到原型上;类本身有 resolve、reject、all、race,用 static 加到类上。构造器 constructor 接收执行器函数,并在内部调用它,同时把 resolve、reject 传给外部。外部一旦调用这两个函数,就会回到类内部修改状态。
怎么做: then 要分三种情况:调用时状态已成功、已失败、仍未改变。前两种直接执行对应回调;第三种先把回调存入数组,等状态改变后再统一执行。then 还要返回新的 Promise,因此要处理回调返回值:是 Promise 还是非 Promise、抛异常还是正常返回。课堂用 try/catch 判断回调异常,并对返回值处理做封装。all 要按数组成员顺序保存结果,而不是按完成顺序;判断全部完成时,课堂用过滤“没有值”的元素再比较长度,也提到可以用计数变量 count。
易错点: 不要把“没有赋值的元素”与“显式赋值为 undefined”混为一谈;filter 会跳过空位,但不会跳过显式 undefined。all 接收的参数必须是可迭代对象,判断时用 Symbol.iterator,不能只靠 try 把可迭代对象转数组,因为非可迭代对象可能得到空数组而不报错。
二、function 版自定义 Promise
为什么需要: 课堂用 function 版对比 class 版,目的是理解“结构不同,核心逻辑相同”。老写法没有 class、没有私有字段,但原型方法、静态方法、构造器逻辑仍然要一一对应。
怎么想: 先用立即执行函数包起来,避免变量污染全局;用 function Promise(executor){} 定义构造函数;实例方法挂到 Promise.prototype,静态方法挂到 Promise 本身。课堂提到可以用 Object.assign(Promise.prototype, { then, catch }),这样对象方法支持简写,便于从 class 版复制。
怎么做: 把 class 版里的 #state、#result、#callbackList 改成实例属性 this.state、this.result、this.callbackList;把 #state 等替换成不带 # 的写法。静态方法改成 Promise.resolve = ...、Promise.reject = ...、Promise.all = ...、Promise.race = ...。复制后要检查箭头函数里的 this:箭头函数没有自己的 this,会往外找,通常仍指向 Promise 实例。
易错点: 立即执行函数末尾的括号不能漏,否则内部代码根本不执行;对象中简写方法之间要加逗号,class 里则不需要;替换私有字段后要全局搜索是否还有 #,否则运行时报错。
三、REST API 风格
为什么需要: 前后端需要一套清晰的接口约定。REST 的核心是:URL 路径表示“操作哪类数据”,请求方式表示“做什么操作”。
怎么想: 同一类数据路径不变,例如 /news:GET 查询,POST 新增,PUT 整体更新,PATCH 局部更新,DELETE 删除。删除单条通常要在路径后带 ID,避免“全删”接口。
怎么做: 新增、更新常把数据放在请求体里,现在流行 JSON,并设置 Content-Type: application/json。查询可在 URL 后加查询参数。
易错点: REST 是前后端约定,不是浏览器强制;实际工作要看后端 API 文档。PUT 和 PATCH 的区别要按课堂演示理解:PATCH 只改传入字段,PUT 容易整体替换。
四、json-server 的安装与启动
为什么需要: 前端开发常遇到后端还没写好、没有真数据的情况。json-server 可以根据一个 JSON 文件快速启动模拟后端服务,让前端先把流程跑起来。
怎么想: 它读取 JSON 文件,最外层必须是对象,里面可以放数组;启动后自动提供 REST 风格接口,并支持 GET、POST、PUT、PATCH、DELETE。
怎么做: 全局安装:npm i -g json-server;查看版本:json-server -v;启动示例:json-server data/transcript.json --port 8088。课堂还提到 --host 参数,默认是 localhost。
易错点: 启动路径写错会导致数据为空,课堂就出现过地址写错后重新改对;--host 指定别名时,访问规则与指定 IP 不同,课堂建议实际开发按后端给的地址请求即可。
五、hosts 文件与域名别名
为什么需要: 浏览器访问域名时,先找本机 hosts 表,再找 DNS。配置 hosts 可以给 127.0.0.1 起别名,方便本地模拟域名。
怎么想: Windows 的 hosts 一般在 C:\Windows\System32\drivers\etc\hosts,macOS 在 /etc/hosts。格式是“IP 空格 别名”,例如 127.0.0.1 shili.com。
怎么做: 若没有权限保存,可先把 hosts 拖到桌面修改,再拖回原目录。改完后可用别名访问本地服务。
易错点: hosts 是系统路径,普通账户可能只读;别名只是本机解析,不会改变真实 DNS;公共电脑的 hosts 可能被改,访问银行、政府类网站要核对域名。
六、用 Apifox/Postman 测试后端 API
为什么需要: 浏览器地址栏只能方便发 GET,测试 POST、PUT、PATCH、DELETE 时写代码成本高。API 测试工具可以直接发请求并查看响应头、响应体。
怎么想: 用 Apifox 或 Postman 新建 HTTP 请求,选择方法、填 URL、按需填 Query、Body、Headers,再发送查看响应。
怎么做: GET 查全部或按 ID 查;POST 用 JSON 请求体新增,json-server 会自动生成 ID;PATCH 只改传入字段;PUT 整体替换;DELETE 在路径后带 ID,通常不需要请求体。查询还可用 ?gender=男 这类参数过滤。
易错点: JSON 里多写尾逗号会校验失败;POST 用查询字符串形式也能加数据,但字段容易不完整,课堂推荐 JSON;PATCH 与 PUT 的替换范围不同,要看清需求。
本节要解决的问题:先有可请求的后端,再谈 Axios
本节标题是“Axios 概述”,但转写稿并没有直接展开 Axios 的 API,而是先把“请求要发到哪里、后端接口长什么样、怎么造测试数据”讲清楚。原因很直接:Axios 是前端发请求的工具,如果没有一个可访问的后端接口,Axios 的演示就无从谈起。
为什么需要:前端程序不能直接连数据库,必须通过后端程序这一层“中间商”取数据、改数据。实际开发中前后端往往同步进行,前端不能等后端全部写完再开工,所以要先准备假数据,把页面和逻辑跑起来。
怎么想:后端常用 REST API 风格:同一个路径,用不同请求方式表达不同操作。针对同一类数据,路径通常不变,变的是请求方法。
怎么做:增删改查可对应为:新增用 POST,删除用 DELETE,更新用 PUT/PATCH,读取用 GET。例如对 news 这一类数据,路径都可以是 /news,删除某一条时再带 ID。
易错点:REST 是前后端约定,不是浏览器强制规则;实际接口要看后端文档。全删接口一般不会提供,因为风险太高,真要“删库跑路”可直接操作数据库,没必要写一个全删接口。
从自定义 Promise 到请求工具:回调传递要理清
为什么需要:Axios 发请求本质上是异步操作,理解 Promise 的状态改变、then/catch 回调注册,有助于后面理解请求成功与失败的处理。
怎么想:转写稿反复强调“传过来、传回去”的过程:new Promise 时把执行器函数传进类内部;类内部调用执行器函数时,又把 resolve/reject 两个函数传到外部;外部调用它们改变状态,相当于又回到类内部执行。then 则是把回调传进去,状态未改变时先存到数组,状态改变后再遍历执行。
怎么做:class 版用私有属性保存状态、结果和回调列表;function 版不支持私有属性,就改用 this.state、this.result、this.callbacks,并把 #state 等替换掉。静态方法包括 resolve/reject/all/race,实例方法包括 then/catch。
易错点:then/catch 不要写成同音误写;function 版用对象简写方法时要加逗号;箭头函数没有自己的 this,要确认它向外找到的是 Promise 实例;then 返回新 Promise,要处理回调异常和返回值类型。
用 json-server 快速搭 REST API
为什么需要:前端开发初期后端可能还没写好,需要快速得到可增删改查的假数据服务。
怎么想:json-server 是一个工具包,全局安装后可直接用命令启动后端服务,不需要自己写后端代码。它根据一个 JSON 文件提供 REST API。
怎么做:先全局安装,再指定 JSON 文件和端口启动。转写中使用的命令是:
bash
npm i -g json-server
json-server --watch data/transcript.json --port 8088
json-server --version易错点:JSON 文件最外层必须是对象,不能是数组;启动时路径写错会出现数据为空;端口可自行指定;安装后可用 --version 验证,转写中版本为 0.17.3。调试时出现过“数据空了”,最后发现是启动地址写错,改对路径后数据恢复。
用测试工具验证后端 API
为什么需要:浏览器地址栏只能发 GET 请求,测 POST、PUT、PATCH、DELETE 不方便,所以需要 API 测试工具,如 Postman、ApiPost。
怎么想:测试工具可以设置请求方法、URL、请求头、请求体、查询参数,并查看响应内容、响应头。
怎么做:POST 添加数据时选 JSON 格式的 body;DELETE 删除时在路径后带 ID,如 /transcript/12;PATCH 只改传入字段,PUT 会整体替换;GET 可在 query 中写过滤条件,如 gender=男&age=56。
易错点:JSON 里多写尾逗号会校验失败;POST 用查询字符串形式提交,数据可能不完整,推荐 JSON;DELETE 不需要请求体;PATCH 和 PUT 的区别要看业务是“局部改”还是“整体替换”。
hosts 与 localhost:地址别写错
为什么需要:localhost 是 127.0.0.1 的别名;json-server --host 绑定别名时,访问地址会受限制。理解 hosts 能避免“地址明明一样却访问不了”的困惑。
怎么想:浏览器输入域名后,先查本机 hosts 表,找不到再查 DNS。hosts 可给 IP 起别名。
怎么做:Windows 的 hosts 一般在 C:\Windows\System32\drivers\etc。没有权限保存时,可先复制到桌面修改,再放回原位置。例如加入:
text
127.0.0.1 shili.com之后访问 shili.com 就指向本机。
易错点:--host 指定的是 IP 时,指向该 IP 的别名和 IP 都可访问;指定的是别名时,通常只能用该别名访问。公共电脑的 hosts 可能被篡改,访问银行、学历查询等网站要看清域名。
回到 Axios:本节准备的接口就是它的请求目标
为什么需要:Axios 用来向后端发请求,必须先有稳定的接口地址和数据结构。
怎么想:先用 json-server 提供 REST API,再用 Axios 对 http://localhost:8088/transcript 这类地址发 GET、POST 等请求。
怎么做:启动服务后,在测试工具里确认接口能返回 JSON,再把这个地址交给 Axios 使用。本节不展开 Axios 的具体 API,只把“后端接口—测试工具—前端请求”这条链路准备好。
易错点:端口、路径、请求方法三者要对齐;请求体格式要按后端要求;不要凭记忆写接口,以 API 文档或测试工具验证结果为准。
本节边界:先说明转写稿实际覆盖了什么
本节标题是“axios 的安装使用”,但给定转写稿里并没有出现 axios 的安装命令、引入方式或请求代码,主要讲的是:自定义 Promise 的回顾、REST API 风格、json-server 的安装启动、hosts 配置以及用 API 测试工具验证后端接口。因此下面不虚构 axios 的安装步骤,而是把“让 axios 有接口可请求”的环境准备整理成教程;axios 的具体安装与调用,应以后续笔记为准。
自定义 Promise 回顾:理解 axios 返回 Promise 的前置知识
为什么需要:转写稿前半段在复习自定义 Promise:实例上有 then、catch,类上有 resolve、reject、all、race 等静态方法。axios 的请求结果同样以 Promise 形式使用,理解状态流转有助于读懂异步代码。
怎么想:重点不是背实现,而是理解“执行器函数传进去、两个回调传出来、状态改变后再执行 then 回调”的来回传递。then 返回新 Promise,回调里要判断异常和返回值类型。
怎么做:复习时抓住三条线:状态如何从 pending 改变;回调列表如何保存;then 返回的 Promise 何时完成。转写稿还提到 all 要按数组成员顺序保存结果,可用索引或计数器判断全部完成。
易错点:不要把“自定义 Promise”误当成 axios 安装步骤;也不要把“没有赋值”和“赋值为 undefined”混为一谈,转写稿特别强调二者在数组处理中不是一回事。
REST API:同一路径,不同请求方式
为什么需要:前端要用 axios 发请求,先要知道后端接口按什么风格设计。REST 风格下,URL 路径可以不变,通过请求方式表达增删改查。
怎么想:针对同一类数据,例如新闻或账单,路径统一;GET 读取,POST 新增,DELETE 删除,PUT 整体修改,PATCH 局部修改。
怎么做:删除通常要在路径后带 ID,例如 /news/1;查询全部用 GET /news;新增用 POST /news 并在请求体放 JSON;修改用 PUT /news/1 或 PATCH /news/1。
易错点:REST 是前后端约定,不是浏览器强制规则;实际接口以 API 文档为准。PUT 往往整体替换,PATCH 只改传入字段;删除接口是否提供“全删”要看后端需求,不能想当然。
用 json-server 快速得到可测试后端
为什么需要:工作中前后端常并行开发,后端接口还没写好时,前端不能干等。json-server 可以基于一份 JSON 文件快速启动模拟 REST API,作为开发和测试工具。
怎么想:先准备一个 JSON 文件,顶层必须是对象,不能是数组;对象里的某个属性可以是数组,作为资源集合。然后全局安装并用命令启动服务。
怎么做:
bash
npm i -g json-server
json-server --version
json-server --watch data/transcript.json --port 8088JSON 结构示意:
json
{
"transcript": [
{ "id": 1, "name": "张才峰" }
]
}启动后访问 http://localhost:8088/transcript 即可拿到数据;还可以用 POST、PUT、PATCH、DELETE 测试增删改。
易错点:JSON 顶层写成数组会不符合要求;路径、端口写错会请求不到;POST 不传 id 时工具会自动生成;PATCH 只改传入字段,PUT 可能把整个对象替换掉;浏览器地址栏只能发 GET,其他请求方式要用测试工具或代码。
API 测试工具与 hosts:验证接口、理解本地域名
为什么需要:写代码测接口成本较高,API 测试工具可以直接向指定地址发各种请求并查看响应头、响应体和状态。hosts 则用于理解本地域名别名,不是 axios 使用的前提。
怎么想:先用测试工具确认接口通不通、数据结构对不对,再写 axios 请求。hosts 的规则是:浏览器先查本机 hosts,找不到再查 DNS;给 127.0.0.1 配别名后,访问该别名就是访问本机。
怎么做:在测试工具里新建 HTTP 请求,选择 GET、POST、PUT、PATCH、DELETE,填写 URL 和 JSON 请求体,查看响应。Windows 的 hosts 一般在 C:\Windows\System32\drivers\etc\hosts,修改需要管理员权限;没有权限时可先拖出修改再放回。
易错点:json-server 启动时若 --host 指定的是别名如 localhost,通常只能用该别名访问;指定 IP 时,指向该 IP 的别名和 IP 都可访问。hosts 配置没有实际业务必要,不要把它当成 axios 安装步骤。等接口可访问后,再按后续笔记执行 axios 的安装与调用;本节不补写转写稿未出现的 axios 命令。
先准备一个能返回数据的后端
为什么需要: axios 只是前端发请求的工具,它必须有一个可访问的接口地址。转写稿里用 json-server 快速搭建模拟 RESTful API:它读取一个 JSON 文件,自动提供增删改查接口,适合前后端并行开发时先造“假数据”。
怎么想: 先把“请求地址、请求方式、请求体”这三件事对应到后端接口,再用 axios 发请求。转写稿里说的“杰森杠 server”应纠正为 json-server,“接身/节森/接信”应理解为 JSON。
怎么做: 准备一个最外层是对象的 JSON 文件,启动类似 json-server --watch data.json --port 8088 的服务;接口地址形如 http://127.0.0.1:8088/transcript。浏览器地址栏只能发 GET,所以 POST、PUT、PATCH、DELETE 要用接口测试工具或 axios 代码验证。
易错点: JSON 文件最外层不能是数组;端口、路径写错会拿不到数据;json-server --host 指定 IP 或别名时,访问地址要与其规则一致,否则可能被拒绝。
axios(config):最本质的发送方式
为什么需要: 当请求方式、地址、请求体、请求头等配置较多时,用一个配置对象最直观,也最接近 axios 的底层调用形式。
怎么想: 把 method、url 以及其他请求配置项都放进一个对象,交给 axios();它返回 Promise,所以在 .then() 里接成功回调和失败回调。
怎么做:
js
// axios 设置请求配置项
axios({
method: 'GET',
url: 'http://127.0.0.1/server',
其他请求配置项...
})
.then(成功回调, 失败回调);易错点: 不要把请求体直接塞到 axios(config) 的外层;POST/PUT/PATCH 的数据应放在配置对象的 data 里。失败回调是 .then() 的第二个参数,不要误以为只能写一个成功回调。
axios(url[, config]):地址与配置分开
为什么需要: 实际开发中 URL 往往固定,变化的只是 method、params、data 等配置,把地址单独拿出来更简洁。
怎么想: 第一个参数是 URL,第二个参数才是请求配置项;如果不传第二个参数,就用默认配置。
怎么做:
js
// axios 第一个参数是URL,第二个参数是请求配置项
axios('http://127.0.0.1/server', {
method: 'GET',
其他请求配置项...
})
.then(成功回调, 失败回调);易错点: 第二个参数是“配置项”,不是请求体;POST 的请求体在别名方法里是第二个参数,在 axios(config) 里则要写成 data。
request 与方法别名:让语义更清楚
为什么需要: 每次都写 method 容易重复,方法别名能让代码一眼看出是 GET 还是 POST。
怎么想: axios.request(config) 等同于 axios(config);get/delete 的参数是 url[, config],post/put 是 url[, data, config],patch 是 url[, data[, config]]。
怎么做:
js
// 请求方法别名
axios
.get('http://127.0.0.1/server', {请求配置项...})
.then(成功回调, 失败回调);
axios
.post('http://127.0.0.1/server', {请求体}, {请求配置项...})
.then(成功回调, 失败回调);axios(config):通用、最本质的发送任意类型请求的方式。axios(url[, config]):第一个参数是地址,第二个参数是配置项。axios.request(config):等同于axios(config)(了解)。axios.get(url[, config]):发 GET 请求。axios.delete(url[, config]):发 DELETE 请求。axios.post(url[, data, config]):发 POST 请求。axios.put(url[, data, config]):发 PUT 请求。axios.patch(url[, data[, config]]):发 PATCH 请求。
易错点: post 的第二个参数是请求体,不是配置项;get 一般没有请求体;delete 的第二个参数是配置项。转写稿里“破/touch”对应 PUT/PATCH,“敌的”对应 DELETE,“pos”对应 POST,不要被同音字带偏。
用 json-server 验证各方法
为什么需要: 只看参数表容易混,必须用真实接口验证“谁带请求体、谁改整体、谁改局部”。
怎么想: 把 json-server 当后端:GET 查所有或按 ID 查;POST 新增并自动生成 ID;PUT 整体替换;PATCH 只改传入字段;DELETE 路径带 ID 删除。
怎么做: 在接口测试工具里发 POST 时选 JSON 请求体;发 PUT/PATCH 时在 URL 后加 ID 并带请求体;DELETE 只写路径 ID,不需要请求体。验证时看响应和 json-server 数据文件是否变化。
易错点: 浏览器地址栏只能发 GET;POST/PUT/PATCH 不写请求体或格式不对会失败;PUT 容易把未传字段“弄丢”,PATCH 才是局部修改;DELETE 带请求体通常无效。把这些调通后,再回到 axios 的 get/post/put/patch/delete 别名,就能把参数位置对应清楚。
说明:转写稿与本节标题不完全对应
你给的笔记标题是“4 axios 请求配置项”,但转写稿实际覆盖的是:自定义 Promise 回顾、REST API 风格、json-server 模拟后端、hosts 文件、API 测试工具验证接口。转写稿没有展开 axios 的 method、headers、data、baseURL 等请求配置项。为避免编造,本节按转写稿整理为“发请求前的后端 API 准备与测试”。本节转写稿未提供图片,故无图片可保留;命令与路径按转写稿保留。
REST API:同一路径,用请求方式表达增删改查
为什么需要: 前后端要约定一套清晰的接口风格,前端才知道“加数据、删数据、改数据、查数据”分别发什么请求。
怎么想: 不要把动作全塞进 URL 路径里,而是让路径表示“资源”,让请求方式表示“动作”。转写稿中的核心就是:路径不变,请求方式不同,后端做不同的事。
怎么做: 常见约定是:新增用 POST,删除用 DELETE,整体更新用 PUT,局部更新用 PATCH,读取用 GET。例如针对 news 资源,新增是 POST /news,删除是 DELETE /news/:id,读取是 GET /news 或 GET /news/:id。
易错点: REST 是约定,不是强制标准;实际工作要看后端 API 文档。删除单个资源通常要带 id,不要误以为可以随意全删;PUT 与 PATCH 的区别要分清:转写稿明确说 PATCH 偏局部修改,PUT 偏整体替换。
json-server:用假数据快速启动一个模拟后端
为什么需要: 项目开发时前后端常常并行,后端接口还没写好,前端不能干等;需要先有假数据把页面和逻辑跑起来。
怎么想: 找一个工具自动把 JSON 文件变成可请求的后端服务,前端先用它开发测试,联调时再换成真实接口。
怎么做: 转写稿中的安装与启动命令是全局安装 json-server,准备一个 JSON 文件,最外层必须是对象,里面可以放数组数据;然后启动服务并指定端口。示例命令如下:
bash
npm i -g json-server
json-server --version
json-server --watch data/transcript.json --port 8088如果指定主机名,可用:
bash
json-server --watch data/transcript.json --port 8088 --host 127.0.0.1易错点: JSON 文件最外层不能是数组,必须是对象;启动时要写对文件路径;端口不要冲突。转写稿还提醒:--host 指定 IP 时,指向该 IP 的别名和该 IP 都可访问;指定的是别名时,通常只能通过该别名访问。实际工作不必死记,按后端给的地址请求即可。
hosts 文件:本机也能给 IP 起别名
为什么需要: 域名本质上是 IP 的别名,方便人记忆。了解 hosts 能明白“浏览器输入域名后先查哪里”。
怎么想: 浏览器先查本机 hosts 表,找不到再去 DNS 服务器查。hosts 是本机的小型“IP—域名对照表”。
怎么做: Windows 常见路径是:
text
C:\Windows\System32\drivers\etc\hostsmacOS 常见路径转写稿提到在系统目录下。可在 hosts 中写“IP 空格 别名”,例如把 127.0.0.1 配成某个自定义域名。若没有权限直接保存,可先复制出来修改,再放回原位置。
易错点: 系统目录文件可能没有修改权限;改完要放回原路径才生效。不要乱改公共电脑的 hosts,否则可能把正常网站指向错误地址。转写稿也强调:配置 hosts 多数只是让地址“更像域名”,不配置通常也能开发。
API 测试工具:不写页面代码也能验证接口
为什么需要: 只用浏览器地址栏只能发 GET,测 POST、PUT、PATCH、DELETE 很麻烦;需要专门工具向接口发请求并查看响应。
怎么想: 把接口当成独立对象来测:选请求方式、填 URL、按需填请求头和 JSON 请求体,然后看状态、响应头、响应体。
怎么做: 转写稿提到 Postman、ApiPost 一类工具。新建 HTTP 请求,选择 GET/POST/PUT/PATCH/DELETE;GET 一般不需要请求体;POST/PUT/PATCH 可在 body 中选 JSON 并填写对象;删除时在 URL 后带 id。测试查询还可使用 ?字段=值 形式。
易错点: JSON 请求体不要多写尾逗号;PUT 可能整体替换,漏字段会丢字段;PATCH 只改传入字段。浏览器地址栏只能发 GET,不要用它验证写操作。
同音字校正
转写稿中的“杰森杠serv”应为 json-server,“re for API/reful”应为 REST/RESTful,“look host/卢克浩”应为 localhost,“接森/节诊/捷信”应为 JSON,“po慢/ATIpo”应指 Postman、ApiPost 一类 API 测试工具。
响应结构总览
本节笔记给出的是请求成功后拿到的“响应对象”结构。它不是后端单独返回的一段数据,而是客户端封装后交给你的完整结果:既有服务器给的响应体、状态码、响应头,也有客户端为这次请求保存的配置和请求实例。转写稿里在测试后端 API 时反复强调“点发送后看响应内容、响应头”,本质上就是在观察这个结构的不同部分。
本节笔记代码如下:
js
{
// `data` 由服务器提供的响应体
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {},
// 'request'
// `request` is the request that generated this response
// It is the last ClientRequest instance in node.js (in redirects)
// and an XMLHttpRequest instance the browser
request: {}
}为什么需要:如果只把响应体丢给你,调试时就不知道状态码、响应头、请求地址和请求参数,排错会很被动。
怎么想:先分清“服务器给的”和“客户端加的”。data/status/statusText/headers 主要来自服务器;config/request 是客户端为这次请求保存的上下文。
怎么做:拿到响应后先看 status,再看 data,需要排错时再看 headers/config/request。
易错点:不要把整个响应对象当成业务数据;业务数据通常在 data 里。
data:响应体
为什么需要:前端真正要渲染、要判断的内容,多数在响应体里。转写稿中用 json-server 测试时,GET 请求能拿到成绩列表,POST 请求返回新加对象并自动带 ID,DELETE 后返回空,这些都属于响应体表现。
怎么想:data 是“服务器提供的响应体”。后端返回 JSON 时,测试工具里看到的是 JSON 内容;在封装后的响应对象里,通常从 data 取。
怎么做:例如 const { data } = response,再根据 data 是数组、对象还是空值分别处理。
易错点:DELETE 请求可能没有实际响应体,不能一律假设 data 是对象;POST 新增后返回的对象可能带自动生成的 ID,不要自己伪造。
status 与 statusText
为什么需要:只看 data 不能判断请求是否成功,状态码是 HTTP 层的结论。
怎么想:status 是 HTTP 状态码,statusText 是状态信息。转写稿里测试接口时,工具会展示响应状态;调试时要先确认请求是否真的成功,再看业务数据。
怎么做:先判断 status 是否在成功范围,再读 data;不要用 data 是否为空来代替状态判断。
易错点:status 不是业务状态码;后端可能在 200 里返回业务失败信息,也可能用 4xx/5xx 表示请求失败,需要结合接口约定。
headers:响应头
为什么需要:响应头能告诉你内容类型、缓存、跨域等信息。转写稿里提到 json-server 返回 JSON 时,响应头里能看到 Content-Type: application/json,这就是判断响应格式的依据。
怎么想:headers 是服务器响应的头,不是请求头;请求头在 config.headers 里。
怎么做:需要判断内容类型时读 headers['content-type'],注意头字段名大小写不敏感,实际使用时按封装提供的方式取。
易错点:不要把响应头和请求头混在一起;不要假设所有接口都返回 JSON。
config 与 request
为什么需要:排错时要知道这次请求发到哪、带了什么参数、用了什么方法。config 保存为请求提供的配置信息,request 是生成该响应的请求实例。
怎么想:这两个字段主要服务于调试和封装,不是业务数据。转写稿里用测试工具发 GET/POST/PUT/PATCH/DELETE 时,地址、方法、请求体不同,响应结果也不同;回到代码里,config 能帮你确认当时到底发了什么。
怎么做:排查“为什么返回不对”时,打印 config.url、config.method、config.data 等,与测试工具里的请求对照。
易错点:不要把 config 当响应体;request 在浏览器和 Node 环境里具体实例不同,不要依赖它的内部细节做业务判断。
调试与验证
为什么需要:响应结构不是背出来的,是在测试工具和浏览器里对照出来的。转写稿中先用 Apifox/Postman 这类工具发请求,观察响应内容、响应头;浏览器地址栏只能发 GET,POST/PUT/PATCH/DELETE 要用工具或代码。
怎么想:先固定请求方法和地址,再看响应区:状态、响应头、响应体分别对应 status/headers/data。用 json-server 测试时,POST 后数据里多出带 ID 的新对象,PATCH 只改传入字段,PUT 会整体替换,DELETE 后数据消失,这些都是验证响应结构的现场。
怎么做:发一次 GET 看列表;发一次 POST 看返回的新对象;发一次 DELETE 看空响应;再对照代码里的 response.data/status/headers/config。
易错点:不要只看“页面有没有数据”,要看状态和响应头;不要混淆 PATCH 与 PUT 的返回结果;测试工具里请求体选 JSON 时,注意不要多写尾逗号,转写稿中就出现过数据校验失败。
课堂画面






代码示例
示例 1:axios 的三种发送方式 + 响应结构
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Axios 基本使用 —— 三种发送方式</title>
</head>
<body>
<button id="btn1">axios(config) 发 GET</button>
<button id="btn2">axios(url, config) 发 GET</button>
<button id="btn3">axios.get(url, config) 发 GET</button>
<pre id="out"></pre>
<!-- 引入 axios(也可用 npm 安装后 import) -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.8/dist/axios.min.js"></script>
<script>
const out = document.getElementById('out');
const print = (obj) => (out.textContent = JSON.stringify(obj, null, 2));
// 1. axios(config):通用 / 最本质的发送任意类型请求的方式
document.getElementById('btn1').onclick = function () {
axios({
method: 'GET',
url: 'http://127.0.0.1:8088/transcript'
}).then(
// 成功回调
function (response) {
print({
data: response.data, // 服务器提供的响应体
status: response.status, // HTTP 状态码
statusText: response.statusText,
headers: response.headers,
config: response.config // 本次请求的配置信息
});
},
// 失败回调
function (error) {
out.textContent = '请求失败:' + error.message;
}
);
};
// 2. axios(url, config):第一个参数是地址,第二个参数是请求配置项
document.getElementById('btn2').onclick = function () {
axios('http://127.0.0.1:8088/transcript', {
method: 'GET',
params: { gender: '男' } // 会被拼成 ?gender=男
}).then(
(res) => print(res.data),
(err) => print(err.message)
);
};
// 3. 请求方法别名:axios.get(url[, config])
document.getElementById('btn3').onclick = function () {
axios
.get('http://127.0.0.1:8088/transcript', { params: { age: 56 } })
.then((res) => print(res.data))
.catch((err) => print(err.message));
};
</script>
</body>
</html>关键行与易错点
axios(config)是“最本质”的写法,axios(url, config)只是它的语法糖——第一个参数最终会被放进config.url。- 三种写法返回的都是 Promise,所以都能
.then(成功回调, 失败回调);then的第二个参数就是失败回调,和.catch作用等价。 - 最大的坑:真正的数据在
response.data里,response本身是{ data, status, statusText, headers, config, request }这样一个包裹对象,直接打印response会看到一堆状态码、请求头,容易误以为数据没拿到。 axios.get(url, config)的第二个参数是请求配置项,不是请求体;要带查询参数用config.params。
示例 2:请求方法别名 + REST 风格增删改查(配合 json-server)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>请求方法别名 —— REST 风格增删改查</title>
</head>
<body>
<button id="get">查 GET</button>
<button id="post">增 POST</button>
<button id="patch">改 PATCH(局部)</button>
<button id="put">改 PUT(整体)</button>
<button id="del">删 DELETE</button>
<pre id="out"></pre>
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.8/dist/axios.min.js"></script>
<script>
// json-server 启动后提供的接口地址:同一个 URL,不同请求方式干不同的事
const BASE = 'http://127.0.0.1:8088/transcript';
const out = document.getElementById('out');
const print = (tag, res) =>
(out.textContent += `[${tag}] ${res.status} ${JSON.stringify(res.data)}\n`);
// 查:axios.get(url[, config])
document.getElementById('get').onclick = () =>
axios.get(BASE).then((res) => print('GET', res));
// 增:axios.post(url, data[, config]) —— 第二个参数是请求体
document.getElementById('post').onclick = () =>
axios
.post(BASE, { name: '刘十四', age: 45, gender: '女', score: 61 })
.then((res) => print('POST', res));
// 改(局部):axios.patch(url[, data[, config]]) —— 只改传进去的字段
document.getElementById('patch').onclick = () =>
axios.patch(BASE + '/9', { age: 51 }).then((res) => print('PATCH', res));
// 改(整体):axios.put(url[, data[, config]]) —— 整个对象被替换
document.getElementById('put').onclick = () =>
axios
.put(BASE + '/9', { name: '萧十一郎110', age: 51 })
.then((res) => print('PUT', res));
// 删:axios.delete(url[, config]) —— 没有请求体,第二个参数是配置项
document.getElementById('del').onclick = () =>
axios.delete(BASE + '/12').then((res) => print('DELETE', res));
</script>
</body>
</html>关键行与易错点
- 参数顺序是本节最容易错的地方:
get/delete是(url[, config]);post/put/patch是(url[, data[, config]])——请求体在第二、配置项在第三,把{ headers }写到第二位会被当成请求体发出去。 delete没有请求体,axios.delete(BASE + '/12')里的12必须写在 URL 路径上,后端靠它定位要删哪条。PATCH只改传入的字段,PUT会把整个对象替换掉(传了两个字段,其余字段就没了)——转写稿里现场演示过这个区别。- REST 风格的核心是:路径不变,靠请求方式区分增删改查。后端用 json-server 模拟:
npm i -g json-server全局安装后用json-server --watch data/transcript.json --port 8088启动,数据文件最外层必须是对象不能是数组。 - 若用
--host指定了localhost,就只能用localhost访问;指定成 IP,则该 IP 及其别名都能访问——地址不一致会直接连不上。
示例 3:完整页面 —— 表格渲染 + 增删改查
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>json-server + Axios 增删改查</title>
<style>
body { font-family: sans-serif; margin: 24px; }
table { border-collapse: collapse; margin-top: 12px; }
th, td { border: 1px solid #ccc; padding: 6px 12px; }
button { cursor: pointer; }
#msg { color: #c00; min-height: 20px; }
</style>
</head>
<body>
<h3>成绩表</h3>
<form id="addForm">
<input name="name" placeholder="姓名" required>
<input name="age" placeholder="年龄">
<input name="gender" placeholder="性别">
<input name="score" placeholder="成绩">
<button>添加</button>
</form>
<p id="msg"></p>
<table>
<thead>
<tr><th>ID</th><th>姓名</th><th>年龄</th><th>性别</th><th>成绩</th><th>操作</th></tr>
</thead>
<tbody id="tbody"></tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.8/dist/axios.min.js"></script>
<script>
const BASE = 'http://127.0.0.1:8088/transcript';
const tbody = document.getElementById('tbody');
const msg = document.getElementById('msg');
// 渲染列表:注意用的是响应里的 data
function render(list) {
tbody.innerHTML = list.map((it) => `
<tr>
<td>${it.id}</td>
<td>${it.name}</td>
<td>${it.age ?? ''}</td>
<td>${it.gender ?? ''}</td>
<td>${it.score ?? ''}</td>
<td>
<button data-act="edit" data-id="${it.id}">改分</button>
<button data-act="del" data-id="${it.id}">删除</button>
</td>
</tr>`).join('');
}
// 查:页面一进来就拉一次
function load() {
axios.get(BASE)
.then((res) => render(res.data))
.catch((err) => (msg.textContent = '加载失败:' + err.message));
}
// 增:提交表单 → POST 请求体
document.getElementById('addForm').onsubmit = function (e) {
e.preventDefault(); // 阻止表单默认跳转
const data = Object.fromEntries(new FormData(this).entries());
axios.post(BASE, data)
.then((res) => {
msg.textContent = '添加成功,服务器生成的 ID = ' + res.data.id;
this.reset();
load(); // 重新拉列表
})
.catch((err) => (msg.textContent = '添加失败:' + err.message));
};
// 删 / 改:事件委托,一个监听管所有按钮
tbody.onclick = function (e) {
const btn = e.target.closest('button');
if (!btn) return;
const id = btn.dataset.id;
if (btn.dataset.act === 'del') {
axios.delete(BASE + '/' + id)
.then(() => load())
.catch((err) => (msg.textContent = '删除失败:' + err.message));
}
if (btn.dataset.act === 'edit') {
const score = prompt('新的成绩:');
if (score === null) return; // 用户点了取消
axios.patch(BASE + '/' + id, { score: Number(score) })
.then(() => load())
.catch((err) => (msg.textContent = '修改失败:' + err.message));
}
};
load();
</script>
</body>
</html>关键行与易错点
e.preventDefault()必须写,否则表单提交会刷新页面,axios 请求刚发出页面就重载了,看起来像“没反应”。- 增删改成功后一定要重新
load():服务器返回的只是那一条记录,页面列表不会自己更新。 - 修改成绩用
patch(只改score),如果用put且只传{ score },其余字段会被整体替换掉,数据就残缺了。 res.data.id是 json-server 自动生成的 ID——POST 时不用自己传id。res.data为空(DELETE 的响应就是空的)时不要去做res.data.xxx,会报Cannot read properties of undefined。- json-server 默认带 CORS 头,可以直接跨端口请求;如果报跨域/连不上,先检查服务是否启动、端口 8088 与 URL 是否一致、
--host指定的主机名与请求地址是否匹配。
常见错误
1. 把请求体塞进 GET 的第二个参数
- 现象:
axios.get('/list', { id: 1 })参数发不出去,服务端收不到id,或者报配置项类型错误。 - 原因:
axios.get(url[, config])第二个位置是配置项,不是数据;data只存在于 post/put/patch 的签名里。 - 修法:GET 的参数写进
config.params;确实要发请求体就换post/put/patch。
2. 用 POST 时把配置项当成了请求体
- 现象:服务端收到的 body 是
{headers:{...}, timeout:5000}这种东西,业务字段全丢。 - 原因:
axios.post(url[, data, config])是三个位置,data在第二、config在第三;写两个参数时第二参被当成 data。 - 修法:
axios.post(url, { name:'x' }, { timeout: 5000 });不发 body 时显式写null占位。
3. 直接把响应对象当数据用
- 现象:
res.name是undefined,控制台打印res里却"能看到"数据。 - 原因:axios 返回的是响应结构
{ data, status, statusText, headers, config, request },业务数据在res.data里,展开时看着像"就在里面"。 - 修法:
const { data } = await axios.get(url);养成先看status再用data的习惯。
4. 只写成功回调,认为出错会自己"冒出来"
- 现象:接口 404/500 时页面毫无反应,控制台一条红色报错;或者 4xx 时业务代码照常往下跑。
- 原因:默认只有 2xx 才 resolve,其余走 reject;
.then(成功)单参写法把失败分支丢了,未捕获的 rejection 只会打日志。 - 修法:
.then(成功).catch(失败),或在async里用try/catch包住 await;需要特殊状态码时显式配validateStatus。
5. async 函数里忘记 await / then 链里忘记 return
- 现象:拿到的值打印出来是
Promise {<pending>},或者后续代码比请求先执行。 - 原因:
axios(...)返回 Promise,不await就只是"发起"了请求;.then回调里不return,下一环拿到的是undefined。 - 修法:
await到底;链式里每一步都return;封装的请求函数记得return axios(...)。
6. 请求地址与 json-server 的实际资源路径对不上
- 现象:
404 Not Found,或者拿到{}、拿到整个对象而不是数组。 - 原因:资源路径由 JSON 顶层 key 决定(
{ "transcript": [...] }→/transcript);改/删必须带/:id,查询条件要放 query 而不是拼在路径上。 - 修法:先浏览器直接打开根地址看它给出的路由说明,再照着拼;改删一律
/资源/id。
7. 服务地址写 127.0.0.1,服务却按 localhost 绑定(或反之)
- 现象:浏览器能开,代码里请求被拒 /
ERR_CONNECTION_REFUSED。 - 原因:
--host指定别名时只接受该别名访问;指定 IP 时该 IP 及其别名都可访问。另外 json-server 没启动、端口写错也会同样报错。 - 修法:统一用同一个主机名;不确定就先在地址栏验证服务活着,再写进代码。
练习
签名纠错:给出 5 行写坏的 axios 调用(含 GET 传 data、POST 少参数、delete 用 body、params 拼在 url 上、config 与 data 位置颠倒),逐行改对并说明改的是第几个参数。
响应结构拆解:对同一个接口分别用
axios(config)、axios(url, config)、axios.get三种写法请求,打印完整响应对象,标出data / status / headers / config各自的来源,并写出"只取业务数据"的最短一行代码。RESTful 全流程:用 json-server 起一个自己的 JSON(顶层是一个对象、里面至少两个数组资源),用测试工具依次完成:查全部 → 按 id 查 → 带 query 条件查 → 新增 → PATCH 改一个字段 → PUT 整体覆盖 → DELETE 一条。把每一步的方法 + 路径 + 是否有请求体记录成表。
axios 接入:把第 3 题的七个操作改用 axios 实现,封装成一个模块(至少包含
getList(params)、getOne(id)、add(data)、update(id, data)、remove(id)),要求统一处理错误,调用方只拿到data。错误分支演练:故意制造三种失败——请求不存在的 id、把服务关掉、把 url 写错域名——分别观察进入的是
.catch还是then的成功回调,记录error.message、error.response、error.request三者的差异。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 自定义Promise-class版回顾 | 18:18 |
| 2 | 自定义Promise-function版 | 21:24 |
| 3 | RestAPI介绍 | 06:23 |
| 4 | json-server的安装和启动 | 17:35 |
| 5 | 配置hosts文件 | 15:14 |
| 6 | 使用测试工具测试后端API | 17:54 |
小结
- axios 的所有调用形式最终都归一到
axios(config),方法别名只是"参数位置被固定"的语法糖——记住位置比记住 API 名单更重要。 data与config的位置差异是最高频错误源:GET/DELETE 只有 config,POST/PUT/PATCH 是(url, data, config)。- 永远记住返回的是响应对象而不是数据本身,
status判成败、data取内容、config回溯请求。 - Promise 的错误分支必须显式接住,
catch或try/catch二者选其一,不要指望控制台替你兜底。 - 前端先行时用 json-server 造数据是标准做法:它把"方法 + 路径"直接映射成增删改查,正好用来验证你对 RESTful 的理解。
- PATCH 是局部改、PUT 是整体替换,选哪个取决于业务是"改一个字段"还是"提交整份表单"。
- 请求地址的每一个字符都有来源:资源名来自 JSON 顶层 key,主机名来自服务绑定配置,端口来自启动参数——对不上就先在浏览器验证,再怀疑代码。
- 调试顺序固定为:服务是否活着 → 地址是否正确 → 方法与参数位置是否正确 → 响应结构是否取对,按这个顺序排错能省掉大半时间。