uni-app 与 Spring Boot 后端对接:请求封装与错误处理

uni-app 与 Spring Boot 后端对接:请求封装与错误处理
移动端和后端的对接远不止调接口三个字——上传 token 怎么带、网络断了怎么提示、统一错误码映射、超时重试。这篇文章把 uni-app 对接 Spring Boot 的所有坑和最佳实践一次讲清。一、统一的请求封装// utils/request.js import { useUserStore } from /stores/user const BASE_URL_MAP { development: http://192.168.1.100:8080, // 局域网调试 production: https://api.your-domain.com } const BASE_URL BASE_URL_MAP[process.env.NODE_ENV] const request (options) { return new Promise((resolve, reject) { const userStore useUserStore() uni.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, Authorization: userStore.token ? Bearer ${userStore.token} : , ...options.header }, timeout: options.timeout || 15000, success: (res) { const { code, data, msg } res.data // 成功 if (code 200) { resolve(data) return } // Token 过期 if (code 401) { userStore.logout() uni.reLaunch({ url: /pages/login/index }) reject(new Error(登录已过期)) return } // 业务异常 uni.showToast({ title: msg || 操作失败, icon: none }) reject(new Error(msg)) }, fail: (err) { // 网络层面的错误 const errorMsg getNetworkErrorMsg(err) uni.showToast({ title: errorMsg, icon: none }) reject(err) } }) }) } // 网络错误信息映射 function getNetworkErrorMsg(err) { if (err.errMsg?.includes(timeout)) return 请求超时请重试 if (err.errMsg?.includes(fail)) return 网络异常请检查网络 return 请求失败 } export default request二、与 Spring Boot 后端的格式约定2.1 统一响应格式// AjaxResult.java public class AjaxResult extends HashMapString, Object { public static final int SUCCESS 200; public static final int UNAUTHORIZED 401; public static final int FORBIDDEN 403; public static final int ERROR 500; public static AjaxResult success(Object data) { AjaxResult result new AjaxResult(); result.put(code, SUCCESS); result.put(data, data); result.put(msg, 操作成功); return result; } public static AjaxResult error(int code, String msg) { AjaxResult result new AjaxResult(); result.put(code, code); result.put(msg, msg); return result; } }2.2 后端全局异常处理RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(BusinessException.class) public AjaxResult handleBusinessException(BusinessException e) { return AjaxResult.error(e.getCode(), e.getMessage()); } ExceptionHandler(Exception.class) public AjaxResult handleException(Exception e) { log.error(系统异常, e); return AjaxResult.error(500, 系统异常请联系管理员); } }2.3 分页结果格式约定// PageResult.java public class PageResult { private List? rows; private long total; public static AjaxResult page(List? rows, long total) { MapString, Object map new HashMap(); map.put(rows, rows); map.put(total, total); return AjaxResult.success(map); } }// Controller GetMapping(/list) public AjaxResult list(RequestParam int pageNum, RequestParam int pageSize) { PageHelper.startPage(pageNum, pageSize); ListCustomer list customerService.selectList(); return PageResult.page(list, new PageInfo(list).getTotal()); }三、文件上传对接3.1 前端上传// api/upload.js export async function uploadFile(filePath, type image) { return new Promise((resolve, reject) { uni.uploadFile({ url: BASE_URL /common/upload, filePath: filePath, name: file, formData: { type }, header: { Authorization: Bearer useUserStore().token }, success: (res) { const { code, data, msg } JSON.parse(res.data) if (code 200) resolve(data.url) else reject(new Error(msg)) }, fail: reject }) }) }3.2 后端接收PostMapping(/common/upload) public AjaxResult upload(RequestParam(file) MultipartFile file) { String url fileService.upload(file); return AjaxResult.success(Map.of(url, url)); }四、WebSocket 实时推送uni-app 版车间电子看板需要实时展示生产进度用 WebSocket// utils/websocket.js class WebSocketClient { constructor() { this.socketTask null this.reconnectTimer null this.reconnectCount 0 } connect() { const userStore useUserStore() this.socketTask uni.connectSocket({ url: wss://api.your-domain.com/ws/mes?token${userStore.token}, success: () console.log(WebSocket 连接中...) }) this.socketTask.onOpen(() { console.log(WebSocket 已连接) this.reconnectCount 0 }) this.socketTask.onMessage((res) { const data JSON.parse(res.data) // 分发给对应页面 uni.$emit(ws-message, data) }) this.socketTask.onClose(() { this.reconnect() }) this.socketTask.onError(() { this.reconnect() }) } reconnect() { if (this.reconnectCount 5) return this.reconnectCount this.reconnectTimer setTimeout(() { this.connect() }, 3000 * this.reconnectCount) // 递增等待 } send(data) { if (this.socketTask) { this.socketTask.send({ data: JSON.stringify(data) }) } } close() { if (this.socketTask) { this.socketTask.close() } if (this.reconnectTimer) { clearTimeout(this.reconnectTimer) } } } export const wsClient new WebSocketClient()五、错误处理体系// utils/errorHandler.js export const ERROR_MAP { 400: 请求参数有误, 401: 登录已过期, 403: 没有操作权限, 404: 请求的资源不存在, 500: 服务器异常, 502: 网关异常, 503: 服务暂时不可用 } export function handleHttpError(code, defaultMsg) { const msg ERROR_MAP[code] || defaultMsg || 未知错误 if (code 401) { // 避免多次弹窗 uni.showModal({ title: 登录过期, content: 您的登录已过期请重新登录, showCancel: false, success: () { const userStore useUserStore() userStore.logout() } }) } else if (code 403) { uni.showToast({ title: msg, icon: none }) } else { uni.showToast({ title: msg, icon: none }) } }六、开发调试技巧6.1 真机调试本地后端// 使用局域网 IP const BASE_URL http://192.168.1.100:8080 // 如果后端加了跨域 // 小程序不需要关心跨域App 端需要后端配置 CORS// 后端 CORS 配置 Configuration public class CorsConfig { Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(*) .allowedHeaders(*) .allowCredentials(true); } }; } }6.2 请求日志// 开发环境下打印请求日志 if (process.env.NODE_ENV development) { console.log([Request] ${options.method} ${options.url}) console.log([Request Data], options.data) }七、总结uni-app 对接 Spring Boot 的核心要点要点做法统一响应格式后端AjaxResult前端根据code分流Token 传递请求拦截器自动注入 Header文件上传uni.uploadFileMultipartFile实时推送uni.connectSocket Spring WebSocket错误码映射前后端一致维护ERROR_MAP真机调试局域网 IP CORS 配置如果你也在独立开发产品或者对制造业数字化感兴趣欢迎关注这个公众号。我会持续分享从代码到产品的全过程——包括成功的经验也包括踩过的坑。一个人的产品之路不孤单。原创作者 MqCode全栈开发者印刷包装行业 MESCRM 系统独立开发欢迎自由转发。