五金机械设备网站模板建设,湛江网站建设优化推广,免费空间官网,传奇官方网站核心目标正确建立通信#xff0c;实现跨域支持、请求解析、统一响应、环境适配核心配置项1. 跨域配置#xff08;最关键#xff01;前端跨域请求必配#xff09;前端运行在 http://localhost:8080/3000 等端口#xff0c;后端运行在 http://localhost:3001 等端口#xf…核心目标正确建立通信实现跨域支持、请求解析、统一响应、环境适配核心配置项1. 跨域配置最关键前端跨域请求必配前端运行在http://localhost:8080/3000等端口后端运行在http://localhost:3001等端口浏览器会触发「同源策略」拦截请求必须配置 CORS跨域资源共享。1.1 安装依赖npm install cors --save1.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配置允许认证头并封装认证中间件依赖名称安装命令核心作用jsonwebtokennpm install jsonwebtoken --save生成 JWT Token 验证 Token 合法性核心express-jwt可选npm install express-jwt --save简化 Express 中 JWT 认证中间件的编写替代手动验证crypto-jsnpm 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_SECRETyour_jwt_secret_key_123456 # JWT 密钥随机字符串越长越安全 JWT_EXPIRES_IN2h # Token 过期时间 PWD_SALTyour_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;