4.前后端联调(Vue3+Vite + Express + MySQL)

核心目标

正确建立通信,实现跨域支持、请求解析、统一响应、环境适配

核心配置项

1. 跨域配置(最关键!前端跨域请求必配)

前端运行在 http://localhost:8080/3000 等端口,后端运行在 http://localhost:3001 等端口,浏览器会触发「同源策略」拦截请求,必须配置 CORS(跨域资源共享)。

1.1 安装依赖

复制代码
npm install cors --save

1.2 在app.js中配置

复制代码
const express = require('express');
const cors = require('cors');
const app = express();
// 基础跨域配置(允许所有前端域名访问,开发环境可用)
app.use(cors());
// ------------------------进阶---------------------------
// 生产环境精准配置(仅允许指定前端域名)
// app.use(cors({
//   origin: [
//     'https://your-frontend-domain.com', // 生产环境前端域名
//     'http://localhost:8080' // 开发环境前端本地地址
//   ],
//   credentials: true, // 允许前端携带Cookie(如登录态)
//   methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 允许的请求方法
//   allowedHeaders: ['Content-Type', 'Authorization'] // 允许的请求头
// }));
2. 请求体解析(前端传参必配)

确保后端能正确解析前端传递的 JSON/表单/文件 等参数,需配置 Express 内置中间件:

复制代码
// 解析 JSON 格式请求体(前端 axios.post 传 JSON 必配)
app.use(express.json()); 

// 解析表单格式请求体(如前端 form 提交、axios 传 application/x-www-form-urlencoded)
app.use(express.urlencoded());
3.端口与地址配置(前端能访问到后端)

确保后端监听的地址和端口对前端可见

进阶配置(生产环境必做)

1. 接口前缀统一(简化前端请求路径)

所有接口统一前缀(如 /api),前端无需拼接零散路径:

复制代码
// 手动挂载(适合少量路由)
app.use('/api', userRouter);
app.use('/api', goodsRouter);

// 自动挂载使用之前封装的自动挂载方法
2. 错误处理(避免前端收到无意义的报错)

配置全局错误中间件,捕获所有未处理的异常,返回统一格式:

复制代码
全局错误处理中间件(必须放在所有路由之后)
app.use((err, req, res, next) => {
  console.error('全局异常:', err.stack); // 后端记录错误日志
  // 给前端返回统一错误格式
  error(res, '服务器内部错误', 500, err);
});

// 404 处理(前端访问不存在的接口)
app.use((req, res) => {
  error(res, '接口不存在', 404);
});
3. 请求头与认证(如 Token 验证)

若前端需要携带登录态(如 JWT Token),配置允许认证头,并封装认证中间件:

|--------------------|-----------------------------------|---------------------------------------|
| 依赖名称 | 安装命令 | 核心作用 |
| jsonwebtoken | npm install jsonwebtoken --save | 生成 JWT Token + 验证 Token 合法性(核心) |
| express-jwt (可选) | npm install express-jwt --save | 简化 Express 中 JWT 认证中间件的编写(替代手动验证) |
| crypto-js | npm install crypto-js --save | 对敏感信息(如用户密码)进行加密(如 MD5/SHA256),避免明文存储 |

复制代码
// 跨域配置中允许 Authorization 头(已在上面配置)
// 认证中间件(middleware/auth.js)
const jwt = require('jsonwebtoken');
const { error } = require('../utils/response');

const authMiddleware = (req, res, next) => {
  // 从请求头获取 Token
  const token = req.headers.authorization?.replace('Bearer ', '');
  if (!token) {
    return error(res, '未登录,请先登录', 401);
  }
  try {
    // 验证 Token
    const user = jwt.verify(token, process.env.JWT_SECRET);
    req.user = user; // 挂载用户信息到 req,后续接口可直接使用
    next();
  } catch (err) {
    error(res, 'Token 过期或无效', 401);
  }
};

//  在需要认证的路由中使用
const orderRouter = express.Router();
orderRouter.use(authMiddleware); // 所有订单接口需要登录
orderRouter.post('/', async (req, res) => {
  console.log('当前登录用户:', req.user.id); // 直接使用认证后的用户信息
});
express-jwt(简化中间件)

替代手动编写 Token 验证逻辑,直接通过中间件拦截未认证请求:

复制代码
const expressJwt = require('express-jwt');
const dotenv = require('dotenv');
dotenv.config();

// 全局认证中间件(排除登录/注册接口)
app.use(
  expressJwt({
    secret: process.env.JWT_SECRET,
    algorithms: ['HS256'] // 指定加密算法(必须和生成 Token 时一致)
  }).unless({
    path: ['/api/user/login', '/api/user/register'] // 无需认证的接口
  })
);

// Token 验证失败的全局处理
app.use((err, req, res, next) => {
  if (err.name === 'UnauthorizedError') {
    return error(res, 'Token 过期或无效', 401);
  }
  next(err);
});
crypto-js(密码加密)

用户注册 / 登录时,加密密码后存储到数据库(避免明文):

复制代码
const CryptoJS = require('crypto-js');

// 加密密码(如 MD5)
const encryptPassword = (password) => {
  // 加盐(salt)提升安全性,salt 需配置在环境变量中
  return CryptoJS.MD5(password + process.env.PWD_SALT).toString();
};

// 验证密码(登录时对比加密后的密码)
const checkPassword = (inputPwd, dbPwd) => {
  return encryptPassword(inputPwd) === dbPwd;
};
.env 文件中配置敏感信息,避免硬编码:
复制代码
# .env 文件
JWT_SECRET=your_jwt_secret_key_123456 # JWT 密钥(随机字符串,越长越安全)
JWT_EXPIRES_IN=2h # Token 过期时间
PWD_SALT=your_password_salt_789 # 密码加盐字符串

前端对接示例(以 Axios 为例)

前端需配置请求基地址、请求头、响应拦截器,和后端统一格式适配:

复制代码
// src/utils/request.js(前端 Axios 封装)
import axios from 'axios';

// 配置后端基地址(和后端端口/前缀一致)
const request = axios.create({
  baseURL: 'http://localhost:3001/api', // 后端接口前缀
  timeout: 10000, // 请求超时
  withCredentials: true // 允许携带Cookie(若后端配置了 credentials: true)
});

// 请求拦截器:添加 Token 等请求头
request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截器:统一处理后端返回格式
request.interceptors.response.use(
  (response) => {
    const res = response.data;
    // 后端 success: true 直接返回数据
    if (res.success) {
      return res.data;
    }
    // 业务错误(如参数错、未登录)
    ElMessage.error(res.msg); // 前端提示错误信息
    return Promise.reject(res);
  },
  (error) => {
    // 网络错误/500错误
    ElMessage.error(error.response?.data?.msg || '请求失败');
    return Promise.reject(error);
  }
);

export default request;
相关推荐
Logic1014 小时前
《数据库运维》 郭文明 实验5 数据库性能监视与优化实验核心操作与思路解析
运维·数据库·sql·mysql·计算机网络技术·形考作业·国家开放大学
刺客xs4 小时前
Qt ---- Qt6.5.3 连接MySQL数据库
数据库·qt·mysql
37方寸4 小时前
MySQL系列4
mysql
weixin_462446235 小时前
【原创实践】Node.js 动态生成 SVG 项目规划纸模板 高仿 纸由我 PaperMe
node.js·生成纸张
光影少年5 小时前
postgrsql和mysql区别?
数据库·mysql·postgresql
云和数据.ChenGuang5 小时前
`post_max_size`、`max_execution_time`、`max_input_time` 是 **PHP 核心配置参数**
开发语言·mysql·php·zabbix·mariadb
前端老曹5 小时前
vue3 三级路由无法缓存的终极解决方案
前端·javascript·vue.js·vue
PAQQ5 小时前
ubuntu22.04 搭建 Opencv & C++ 环境
前端·webpack·node.js
wsx_iot6 小时前
MySQL 的 MVCC(多版本并发控制)详解
数据库·mysql