当前位置: 首页 > news >正文

阶段三:Axios 与 Express 前后端通信

从零构建带AI流式对话的Vue2全栈应用-CSDN博客本文是对这篇文章阶段三的讲解

一、阶段三解决什么问题

阶段二的数据写死在前端:

users: [ { id: 1, name: '张三' } ]

这种数据刷新后不会真正变化,也不是从服务器获取。

阶段三开始让数据来自后端:

Vue 页面 ↓ 请求 Express 后端 ↓ 返回 JSON Vue 页面显示结果

核心技术:

HTTP REST API Express Axios Vue 开发代理 请求拦截器 响应拦截器 async/await

二、Express 后端基础

文件:

mock-server/server.js

顶部:

const express = require('express') const app = express() const PORT = 3000

1.require('express')

const express = require('express')

从已经安装的express软件包中读取 Express。

Express 是一个 Node.js 后端框架。

它能帮助我们处理:

GET 请求 POST 请求 PATCH 请求 DELETE 请求 JSON 数据 URL 参数

2. 创建服务器对象

app可以理解成后端服务器。

后面所有接口都写在app上:

app.get(...) app.post(...) app.patch(...) app.delete(...)

3. 设置端口

const PORT = 3000

后端运行后地址是:

http://localhost:3000

localhost表示当前电脑。

3000表示端口。

端口可以理解成一栋楼里的房间号:

localhost:这台电脑 3000:后端程序所在房间 8081:前端程序所在房间

4. 解析 JSON 请求体

app.use(express.json())

前端发送:

{ "name": "张三", "email": "zhangsan@example.com" }

Express 需要把这段 JSON 转成 JavaScript 对象。

有了express.json(),后端才能使用:

req.body.name req.body.email

没有这一行,req.body可能是undefined


三、模拟数据库

let users = [ { id: 1, name: '张三', email: 'zhangsan@example.com', role: 'admin', status: true } ]

这里暂时没有真正数据库。

使用数组模拟数据库。

users 数组 ≈ 用户表 数组中的对象 ≈ 数据库中的一行

因为使用的是内存数组:

新增用户后可以暂时看到 后端重启后数据恢复

这是教学阶段的正常现象。


四、GET 查询接口

app.get('/api/users', (req, res) => { res.json({ code: 0, message: '获取用户列表成功', data: users }) })

app.get

表示处理 GET 请求。

前端请求:

GET /api/users

后端进入这个函数。


reqres

(req, res) => {}

req是 request,请求。

里面有:

req.query:查询参数 req.params:路径参数 req.body:请求体 req.headers:请求头 req.cookies:Cookie

res是 response,响应。

常用方法:

res.json() res.status() res.send() res.redirect()

返回统一格式

res.json({ code: 0, message: '获取用户列表成功', data: users })

统一返回格式:

code:业务状态 message:提示信息 data:真正的数据

成功:

code: 0

失败:

code: 400 code: 401 code: 404 code: 500

五、查询参数

前端请求:

/api/users?keyword=张三&role=admin

后端读取:

req.query.keyword req.query.role

代码:

const keyword = String( req.query.keyword || '' ) .trim() .toLowerCase()

逐步解释:

req.query.keyword || ''

表示有关键词就使用关键词,没有就使用空字符串。

String(...)

确保它是字符串。

.trim()

去掉前后空格。

例如:

" 张三 "

变成:

"张三"
.toLowerCase()

转成小写,方便不区分大小写搜索。


六、数组筛选

const result = users.filter(user => { return user.name.includes(keyword) })

filter()用于筛选数组。

它会逐个检查用户。

return true

保留这个用户。

return false

删除这个用户。

例如:

users.filter(user => { return user.role === 'admin' })

只保留管理员。


七、POST 新增接口

app.post('/api/users', (req, res) => { const name = req.body.name const email = req.body.email const newUser = { id: nextUserId, name, email } nextUserId += 1 users.unshift(newUser) res.status(201).json({ code: 0, message: '新增成功', data: newUser }) })

POST 和 GET 的区别

GET 通常用于查询:

GET /api/users

POST 通常用于新增:

POST /api/users

新增的数据放在请求体中。


users.unshift(newUser)

users.unshift(newUser)

把新用户放到数组最前面。

如果使用:

users.push(newUser)

则会放到最后面。


状态码 201

res.status(201)

HTTP 状态码:

200:请求成功 201:创建成功 400:参数错误 401:没有登录 403:没有权限 404:找不到资源 500:服务器错误

八、PATCH 修改状态

路由:

app.patch('/api/users/:id/status', ...)

其中:

:id

是动态路径参数。

请求:

PATCH /api/users/3/status

后端读取:

req.params.id

得到字符串:

"3"

转换为数字:

const userId = Number(req.params.id)

然后查找用户:

const user = users.find(item => { return item.id === userId })

find()找到第一个符合条件的对象。


九、DELETE 删除用户

const userIndex = users.findIndex(item => { return item.id === userId })

findIndex()返回数组下标。

例如张三在第一个位置:

userIndex === 0

删除:

users.splice(userIndex, 1)

含义:

从 userIndex 位置开始 删除 1 个元素

十、为什么 404 必须放在最后

app.use((req, res) => { res.status(404).json({ code: 404, message: '接口不存在' }) })

Express 从上往下匹配代码。

正确顺序:

GET /api/users POST /api/users PATCH /api/users/:id/status DELETE /api/users/:id 最后处理 404

如果把 404 放最前面:

所有请求都会先匹配 404 后面的接口永远不会执行

十一、Vue 代理vue.config.js

module.exports = defineConfig({ devServer: { proxy: { '^/api': { target: 'http://localhost:3000', changeOrigin: true } } } })

前端代码请求:

/api/users

浏览器实际访问前端服务器:

http://localhost:8081/api/users

Vue 开发服务器发现路径以/api开头,然后转发:

http://localhost:3000/api/users

代理流程:

浏览器 ↓ /api/users Vue 开发服务器 8081 ↓ 转发 Express 后端 3000

十二、Axios 实例request.js

const service = axios.create({ baseURL: '/api', timeout: 10000 })

baseURL

调用:

request({ url: '/users' })

Axios 会组合成:

/api/users

timeout

timeout: 10000

单位是毫秒。

10000 毫秒 = 10 秒

如果后端 10 秒都没有响应,Axios 会认为超时。


十三、请求拦截器

service.interceptors.request.use( config => { console.log(config) return config }, error => { return Promise.reject(error) } )

请求拦截器会在请求真正发出之前执行。

流程:

页面调用 getUsers() ↓ 进入请求拦截器 ↓ 可以修改请求头、打印日志 ↓ 发送到后端

为什么一定要:

return config

因为 Axios 需要继续使用这个请求配置。

不返回,后续请求可能无法正常发出。


十四、响应拦截器

后端返回:

{ "code": 0, "message": "成功", "data": [ { "id": 1 } ] }

响应拦截器:

return responseBody.data

所以页面最终得到的不是整个对象,而是:

[ { id: 1 } ]

页面可以直接:

this.users = result

而不用:

this.users = result.data.data

十五、API 文件user.js

export function getUsers(params) { return request({ url: '/users', method: 'get', params }) }

为什么不直接在页面写 Axios?

因为把接口集中放在src/api中更容易管理。

页面只关心:

getUsers() createUser() deleteUser()

不需要反复写:

axios.get(...) axios.post(...)

这是代码分层:

页面层:控制页面显示 API 层:描述调用哪个接口 request 层:统一处理 Axios 后端层:处理真实业务

十六、created()生命周期

created() { this.fetchUsers() }

created()是 Vue 生命周期钩子。

组件创建完成时自动执行一次。

所以进入页面后,会自动加载用户列表。

不需要用户先点击“查询”。


十七、async/await

async fetchUsers() { const result = await getUsers() this.users = result }

接口请求需要时间,不会立刻返回。

await表示:

等待请求完成,再继续往下执行。

使用await的函数前必须有:

async

错误:

fetchUsers() { const result = await getUsers() }

正确:

async fetchUsers() { const result = await getUsers() }

十八、try/catch/finally

async fetchUsers() { this.loading = true try { this.users = await getUsers() } catch (error) { this.$message.error('加载失败') } finally { this.loading = false } }

执行过程:

开始请求 loading = true ↓ 成功:进入 try 失败:进入 catch ↓ 无论成功失败,都进入 finally loading = false

所以finally非常适合关闭加载动画。


十九、阶段三完整数据流

ApiDemoView.vue 调用 getUsers() ↓ src/api/user.js 配置 GET /users ↓ src/utils/request.js 添加 baseURL /api ↓ 请求 /api/users ↓ Vue 代理到 localhost:3000 ↓ Express app.get('/api/users') ↓ 返回 JSON ↓ 响应拦截器提取 data ↓ this.users = result ↓ el-table 自动更新
http://www.cnnetsun.cn/news/3489129.html

相关文章:

  • 期货Level2与股票逐笔行情数据有什么,如何下载
  • AI-Shoujo HF Patch:模块化增强套件深度解析与实战指南
  • OpenClaw智能代理框架Windows安装与配置指南
  • Three.js 花瓣雨教程
  • AM62L CBASS防火墙配置详解:从硬件隔离到系统安全实践
  • YimMenu终极指南:3步打造GTA5最安全的游戏体验
  • Adobe-GenP 3.0终极指南:三步免费激活Photoshop等Adobe全家桶的完整教程
  • Windows系统清理终极指南:DriverStore Explorer帮你释放数十GB磁盘空间
  • WaveTools深度解析:3步解锁鸣潮高帧率与专业数据分析的终极方案
  • HFSS仿真在T型波导功分器微放电效应分析中的应用
  • Windows 11存储优化与图片管理高阶技巧
  • Adobe破解工具GenP 3.0:三步永久激活Photoshop等专业软件
  • MT7628/7688 UART2串口配置与优化指南
  • 开源图像查看器Tacent View:游戏开发者的纹理处理解决方案
  • 终极LRC歌词制作指南:5分钟学会专业滚动歌词制作
  • 【小白也能轻松玩转龙虾】虾壳云一键部署,新手跟着操作零安装压力(附最新安装包)
  • DFT笔记79
  • TI CSI-2协议引擎寄存器配置与VC FIFO优化实战指南
  • AI3D工作流应该包括哪些环节?用V2Fun从生成推进到可动资产
  • 变频器辅助电源设计:反激式拓扑与多路输出稳压技术
  • GPT Image 2动画生成技术解析与应用实践
  • Facebook SDK接入指南:从开发到优化的全流程解析
  • 3分钟掌握思源宋体CN:开源中文设计字体的完全指南
  • 自制电磁感应断线检测器:低成本精准定位电线断点
  • 【2018-06-02】有关TCP和UDP粘包和消息保护边界
  • 思源宋体TTF完全指南:7种字重免费开源字体全方位应用
  • 漫画翻译工具:翻页即译技术原理与实战应用指南
  • 多机器人协作中的任务分配:从理论到实践
  • Windows热键侦探:三分钟定位快捷键冲突的神器
  • 掌握vJoy虚拟摇杆:从零构建专业级游戏控制解决方案