Xuan's blog - 前端开发
type: channel
link: https://blog.ybyq.wang/category/front-end/
items: 基于Spring Boot + Vue.js的GPT AI聊天应用：从开发到部署的完整实践
items: 前端开发中嵌入B站视频播放器：解决high_quality=1 失效的问题
items: 智慧零工平台前端开发实战：从uni-app到跨平台应用
items: 解决uniapp小程序轮播图尺寸问题
items: uniapp-文件查找失败: ‘@dcloudio/uni-ui/lib/uni-icons/uni-icons.vue‘
items: Uniapp 自定义 Tabbar 实现教程
items: H5网站接入微信登录详细步骤
items: Ajax和axios有什么区别？
items: 基于uniapp+vant的健身会员管理系统h5前端

基于Spring Boot + Vue.js的GPT AI聊天应用：从开发到部署的完整实践
type: item
date: 2025-09-23T21:57:00+08:00
description: 前言一个人一个下午做成的，为了应对周四的作业答辩。🚀 项目概述本文将详细介绍一个基于Spring Boot后端和Vue.js前端的GPT AI聊天应用的完整开发流程。该项目集成了OpenAI、阿里云通义千问、DeepSeek、豆包、Kimi等多个主流AI平台，支持文本对话和图像生成功能，并实现了用户认证、会话管理、管理员面板、用户统计等完整的业务功能。体验地址：https://gpt.xuan.cyou/技术栈后端: Spring Boot 3.5.5, Java 17, SQLite, JPA/Hibernate前端: Vue.js 3, Vite, Pinia, JavaScript ES6+AI集成: OpenAI GPT-4, 阿里云通义千问, DeepSeek, 豆包, Kimi部署: 宝塔面板, Nginx, SSL证书📁 项目架构GPT-AI-Project/ ├── gpt-ai-java/ # Spring Boot 后端 │ ├── src/main/java/ │ │ ├── controller/ # REST API控制器 (用户, AI, 管理员等) │ │ ├── service/ # 业务逻辑层 (多AI平台服务, 用户统计等) │ │ ├── entity/ # 数据实体 (用户, 对话历史, 统计数据等) │ │ ├── config/ # 配置类 │ │ └── adopter/ # AI平台适配器 (OpenAI, Ali, DeepSeek, Kimi等) │ ├── src/main/resources/ │ │ └── application.yaml # 应用配置 │ └── pom.xml # Maven依赖配置 └── frontend/ # Vue.js 前端 ├── src/ │ ├── components/ # Vue组件 │ ├── views/ # 页面视图 (聊天, 图像, 管理面板, 用户后台等) │ ├── api/ # API调用封装 │ └── store/ # 状态管理 (Pinia) ├── public/ # 静态资源 └── package.json # NPM依赖配置🔧 核心功能实现1. 后端核心架构1.1 多AI平台集成项目支持OpenAI和阿里云通义千问两个AI平台，通过适配器模式实现：// AI控制器统一入口 @RestController @RequestMapping("/api/ai") public class AiController { @GetMapping("/chat/text/stream") public SseEmitter streamChat( @RequestParam String platform, @RequestParam String model, @RequestParam String message ) { // 根据平台选择对应的AI服务 (示例) if ("openai".equals(platform)) { return openAiController.sendTextStream(model, message); } else if ("ali".equals(platform)) { return aliAiController.sendTextStream(model, message); } // ... 此处添加对 deepseek, doubao, kimi 等平台的路由逻辑 return null; // or throw an exception } }1.2 流式响应实现使用Server-Sent Events (SSE) 实现实时流式对话：@PostMapping("/chat/text/stream") public SseEmitter sendTextStream(String model, String message) { SseEmitter emitter = new SseEmitter(0L); CompletableFuture.runAsync(() -> { try { // 流式读取AI响应并实时推送 openAIService.sendText(model, message, true, delta -> { emitter.send(SseEmitter.event().name("delta").data(delta)); }); emitter.send(SseEmitter.event().name("done").data("[DONE]")); emitter.complete(); } catch (Exception e…

前端开发中嵌入B站视频播放器：解决high_quality=1 失效的问题
type: item
date: 2025-06-13T20:53:00+08:00
description: 问题背景在前端开发中，我们可能需要嵌入B站视频。使用B站官方播放器时，遇到了以下问题：默认画质被限制在360p高清画质需要登录B站账号部分视频需要大会员才能观看高清版本问题分析默认的B站原生播放器 存在的问题：画质限制：即使设置了high_quality=1和quality=720，实际播放时仍被限制在360p，这两个方法在22年就失效了登录要求：高清画质需要用户登录B站账号会员限制：部分视频的高清版本需要大会员权限解决方案改进后的高清解析播放器[hide] [/hide]优势：画质提升：可以直接获取视频源默认画质，1080p同样生效无需登录：用户无需登录B站账号突破限制：可以观看部分需要大会员的视频总结通过使用视频解析接口，成功解决了B站视频播放器的画质限制问题。希望这个解决方案对你有所帮助，有问题请在评论区交流。

智慧零工平台前端开发实战：从uni-app到跨平台应用
type: item
date: 2025-06-02T17:42:00+08:00
description: 本文将详细介绍我如何使用uni-app框架开发一个支持微信小程序和H5的零工平台前端应用，包含技术选型、架构设计、核心功能实现及部署经验。前言在当今移动互联网时代，跨平台开发已成为提高开发效率的重要手段。本次我选择uni-app框架开发了一个智慧零工平台的前端应用，该平台致力于为零工与雇主搭建高效便捷的双向服务桥梁。项目概况项目名称: 智慧零工平台前端系统技术栈: Vue.js 2.6 + uni-app 3.0 + ColorUI支持平台: 微信小程序 + H5项目地址: GitHub - Gigplatform_front在线预览: https://lgpt.xuan.cyou/技术选型分析为什么选择uni-app？在众多跨平台解决方案中，我最终选择了uni-app，主要基于以下考虑：一套代码多端运行: 支持编译到微信小程序、H5、App等10+平台学习成本低: 基于Vue.js语法，前端开发者容易上手生态完善: 拥有丰富的组件库和插件市场性能优异: 接近原生应用的性能表现社区活跃: DCloud官方维护，社区支持良好核心技术栈{ "前端框架": "Vue.js 2.6.11", "跨平台框架": "uni-app 3.0", "UI组件库": "ColorUI 2.1.6", "样式预处理": "SCSS/SASS", "状态管理": "Vuex", "构建工具": "webpack", "开发工具": "HBuilderX" }项目架构设计整体架构项目采用模块化架构设计，清晰分离业务逻辑和技术实现：smart-gig-platform-front/ ├── api/ # API接口层 ├── components/ # 公共组件 ├── pages/ # 页面文件 ├── employerPackage/ # 雇主端分包 ├── static/ # 静态资源 ├── store/ # 状态管理 ├── colorui/ # UI组件库 └── utils/ # 工具函数分包策略为了优化小程序包体积，我采用了分包加载策略：{ "subPackages": [ { "root": "employerPackage", "name": "employer", "pages": [ "pages/center/index", "pages/postJob/index", "pages/resume/index" ] } ] }这样可以将雇主端功能独立打包，减少主包体积，提升首屏加载速度。核心功能实现1. 双重身份系统这是项目的一大特色功能，用户可以在零工和雇主身份间无缝切换： <view class="identity-switch"> <view class="switch-container"> <view class="switch-item" :class="{ active: currentRole === 'worker' }" @click="switchRole('worker')" > <image src="/static/img/worker-icon.png" /> <text>我是零工</text> </view> <view class="switch-item" :class="{ active: currentRole === 'employer' }" @click="switchRole('employer')" > <image src="/static/img/employer-icon.png" /> <text>我是雇主</text> </view> </view> </view> 2. 地理位置服务实现基于位置的工作推荐功能：// 获取用户位置 async getUserLocation() { try { const res = await uni.getLocation({ type: 'wgs84' }) this.userLocation = { latitude: res.latitude, longitude: res.longitude } // 获取附近工作 await this.getNearbyJobs() } catch (error) { console.error('获取位置失败:', error) uni.showToast({ title: '位置获取失败', icon: 'none' }) } }, // 计算距离 calculateDistance(lat1, lon1, lat2, lon2) { const R = 6371 // 地球半径(km) const dLat = (lat2 - lat1) * Math.PI / 180 const…

解决uniapp小程序轮播图尺寸问题
type: item
date: 2025-05-09T21:03:00+08:00
description: 在微信小程序开发过程中，轮播图组件(swiper)是常用的UI元素，但在实际应用中经常遇到高度不匹配导致的空白问题。本文详细记录了一次轮播图高度优化的完整过程，特别是针对固定宽高比图片的精确适配方案。问题背景在开发"零工市场"微信小程序时，首页包含一个轮播图组件。轮播图使用了三张尺寸为516×145像素的图片，但在实际显示时，轮播图区域为414×207，导致底部出现了大量空白区域，影响了整体页面美观度。初步尝试方案1. 使用自动高度方式最初尝试使用mode="widthFix"来保持图片宽高比，但默认的轮播图组件不会自动适应图片高度，仍然会出现空白。<swiper class="screen-swiper square-dot" :indicator-dots="true" :autoplay="true" :circular="true" :interval="3000" :duration="500"> <swiper-item v-for="(item, index) in banners" :key="index"> <image :src="item.imageUrl" mode="widthFix" class="swiper-image"></image> </swiper-item> </swiper>效果：图片本身按原始比例显示，不会变形但轮播图容器的高度没有随图片高度自动调整，底部依然存在大量空白指示点位置可能不正确，过于靠下2. 尝试强制变形适应接着尝试使用scaleToFill模式强制图片填充整个容器区域，但这种方法会导致图片变形。<swiper class="screen-swiper" :indicator-dots="true" :autoplay="true" :circular="true" :interval="3000" :duration="500" :style="{height: bannerHeight}"> <swiper-item v-for="(item, index) in banners" :key="index"> <image :src="item.imageUrl" mode="scaleToFill" class="swiper-image"></image> </swiper-item> </swiper>效果：图片被强制拉伸填充整个容器，没有空白内容显示不完整视觉效果较差3. 尝试使用aspectFit模式为了保持图片比例不变形，尝试使用aspectFit模式，但这种方式会在上下两侧产生空白。<swiper class="screen-swiper" :indicator-dots="true" :autoplay="true" :circular="true" :interval="3000" :duration="500" :style="{height: bannerHeight}"> <swiper-item v-for="(item, index) in banners" :key="index"> <image :src="item.imageUrl" mode="aspectFit" class="swiper-image"></image> </swiper-item> </swiper>效果：图片保持原始比例，不会变形但图片两侧或上下出现空白，实际显示尺寸较小没有完全利用容器空间最终解决方案经过多次尝试后，找到了最佳解决方案：结合使用外层容器和精确比例计算。核心代码实现1. HTML结构改进：使用外层容器<view class="banner-wrapper" :style="{height: bannerHeight}"> <swiper class="screen-swiper" :indicator-dots="true" :indicator-color="'rgba(255, 255, 255, .3)'" :indicator-active-color="'#ffffff'" :autoplay="true" :circular="true" :interval="3000" :duration="500"> <swiper-item v-for="(item, index) in banners" :key="index" @tap="bannerTap(item)"> <image :src="item.imageUrl" mode="widthFix" class="swiper-image"></image> </swiper-item> </swiper> </view>效果：轮播图外层容器高度通过精确计算，刚好与图片等…

uniapp-文件查找失败: ‘@dcloudio/uni-ui/lib/uni-icons/uni-icons.vue‘
type: item
date: 2025-05-08T17:19:00+08:00
description: 今天在HBuilderX中使用uniapp开发微信小程序时遇到了这个问题：uniapp-文件查找失败：'@dcloudio/uni-ui/lib/uni-icons/uni-icons.vue'，就是找不到uni-ui组件我当时创建项目，选择了一个中间带+的底部带选项卡模板，并没有选择内置uni-ui的项目模板，因为是第一次用，并不知道前者中没有引入uni-ui看了看官方文档，有三种导入方式1、新建项目时，直接选择uni-ui模板2、使用 uni_modules 方式安装组件库，可以直接通过插件市场导入3、使用npm+easycom引入，在终端执行npm i @dcloudio/uni-ui 或 yarn add @dcloudio/uni-ui报错原因我用的是npm+easycom引入的，pages.json中已经引入了easycom，但是文件夹中的内容是空的，找不到文件。解决办法注释掉easycom那几行代码，删掉左边的文件夹，然后使用上面说的第二种方式导入组件即可。

Uniapp 自定义 Tabbar 实现教程
type: item
date: 2025-04-23T01:09:00+08:00
description: 1. 简介在 Uniapp 开发中，自定义 Tabbar 是一个常见的需求。本教程将详细介绍如何实现一个美观且功能完整的自定义 Tabbar，并分享在实现过程中可能遇到的问题和解决方案。2. 实现步骤2.1 创建自定义 Tabbar 组件首先，我们需要创建一个自定义的 Tabbar 组件。以下是完整的实现代码： <view class="custom-tabbar"> <view v-for="(item, index) in tabList" :key="index" class="tabbar-item" :class="{'tabbar-item-active': current === index}" @click="switchTab(item.pagePath)" > <van-icon :name="current === index ? item.selectedIcon : item.icon" class="tabbar-icon" :class="{'tabbar-icon-active': current === index}" /> <text>{{ item.text }}</text> </view> </view> 2.2 配置 pages.json在 pages.json 中需要禁用原生 Tabbar，并配置页面路由：{ "tabBar": { "custom": true, // 启用自定义 Tabbar "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/detail/detail", "text": "详情" }, { "pagePath": "pages/course/course", "text": "课程" }, { "pagePath": "pages/profile/profile", "text": "我的" } ] } }3. 实现过程中的关键点3.1 路由映射使用 TAB_ROUTES 对象来映射路由路径和对应的索引值，这样可以方便地管理当前选中的 tab：const TAB_ROUTES = { '/pages/index/index': 0, '/pages/detail/detail': 1, '/pages/course/course': 2, '/pages/profile/profile': 3 };3.2 样式设计使用 position: fixed 确保 Tabbar 固定在底部添加 env(safe-area-inset-bottom) 适配全面屏手机使用 box-shadow 添加阴影效果实现点击缩放动画效果添加底部指示条3.3 图标处理使用 van-icon 组件（来自 Vant UI）来显示图标，通过 :class 动态切换选中状态。4. 常见问题及解决方案4.1 页面跳转问题问题：使用 uni.switchTab 跳转时可能出现页面不更新的情况。解决方案：确保在 pages.json 中正确配置了 tabBar使用 uni.switchTab 而不是 uni.navigateTo在 watch 中监听路由变化，及时更新选中状态4.2 样式适配问题问题：在不同机型上可能出现底部遮挡或样式错乱。解决方案：使用 env(safe-area-inset-bottom) 适配全面屏设置合适的 z-index 确保层级正确使用 rpx 单位确保在不同设备上显示一致4.3 性能优化问题：频繁切换可能导致性能问题。解决方案：使用 v-for 时添加 :key合理使用 watch 监听路由变化避免在 Tabbar 中加载过多资源5. 扩展功能5.1 添加徽标可以在 Tabbar 项上添加徽标，显示未读消息数量等：<view class="tabbar-item"> <van-icon :name="icon" /> <text>{{ text }}</text> <view v-if="badge" class="badge">{{ badge }}</view> </view>5.2 添加动画效果可以添加更丰富的动画效果，如：.tabbar-item { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .tabbar-item:hover { transform: translateY(-5rpx); }6. 总结通过以上步骤，我们实现了一个功能完整、样式美观的自定义 Tabbar。这个实现方案具有以下特点：支持路由跳转适配不同机型提供良好的视觉反馈性能优化易于扩展

H5网站接入微信登录详细步骤
type: item
date: 2025-04-22T21:18:00+08:00
description: 前期准备1. 注册微信开放平台访问微信开放平台注册开发者账号完成开发者资质认证创建网站应用2. 获取必要的参数AppID：应用的唯一标识AppSecret：应用密钥网站域名：需要配置的网站域名回调域名：用户授权后跳转的域名3. 配置安全域名登录微信开放平台进入"网站应用"管理添加网站域名下载验证文件并上传到网站根目录开发步骤1. 引入微信JS-SDK 2. 配置微信JS-SDKwx.config({ debug: false, // 开启调试模式 appId: '你的AppID', timestamp: '', // 生成签名的时间戳 nonceStr: '', // 生成签名的随机串 signature: '', // 签名 jsApiList: [] // 需要使用的JS接口列表 });3. 实现登录流程3.1 获取授权码function getWechatAuth() { const appid = '你的AppID'; const redirect_uri = encodeURIComponent('你的回调地址'); const scope = 'snsapi_login'; // 授权作用域 const state = '随机字符串'; // 防CSRF攻击 const url = `https://open.weixin.qq.com/connect/qrconnect?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`; window.location.href = url; }3.2 获取访问令牌async function getAccessToken(code) { const appid = '你的AppID'; const secret = '你的AppSecret'; try { const response = await fetch(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${appid}&secret=${secret}&code=${code}&grant_type=authorization_code`); const data = await response.json(); return data; } catch (error) { console.error('获取访问令牌失败:', error); return null; } }3.3 获取用户信息async function getUserInfo(access_token, openid) { try { const response = await fetch(`https://api.weixin.qq.com/sns/userinfo?access_token=${access_token}&openid=${openid}`); const data = await response.json(); return data; } catch (error) { console.error('获取用户信息失败:', error); return null; } }4. 处理回调// 在回调页面处理授权码 const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); const state = urlParams.get('state'); if (code && state) { // 验证state防止CSRF攻击 if (state === '你之前生成的随机字符串') { // 获取访问令牌 const tokenData = await getAccessToken(code); if (tokenData) { // 获取用户信息 const userInfo = await getUserInfo(tokenData.access_token, tokenData.openid); if (userInfo) { // 处理用户信息，如保存到本地存储或发送到服务器 handleUserInfo(userInfo); } } } }注意事项1. 安全相关state参数：必须使用随机字符串，防止CSRF攻击HTTPS：必须使用HTTPS协议域名验证：确保域名与开放平台配置一致密钥保护：AppSecret必须妥善保管，不要暴露在前端2. 用户…

Ajax和axios有什么区别？
type: item
date: 2025-04-17T15:33:00+08:00
description: 在进行前端开发时，我们经常需要和后端进行数据交互。在这个过程中，Ajax和axios是我们最常用的两个工具。今天，我就来和大家聊聊它们的区别。什么是Ajax？Ajax（Asynchronous JavaScript and XML）是一种在网页中实现异步数据交互的技术。简单来说，就是可以在不刷新整个页面的情况下，向服务器发送请求并获取数据。举个生活中的例子：就像你在餐厅点餐，服务员（Ajax）可以帮你把菜单（请求）送到厨房（服务器），然后把做好的菜（响应）端回来，而不需要你亲自去厨房。什么是Promise？在讲axios之前，我们先来了解一下Promise。Promise是JavaScript中处理异步操作的一种方式，你可以把它想象成一个"承诺"。比如你约朋友吃饭：你发出邀请（创建Promise）朋友可能答应（resolve）或拒绝（reject）如果答应，你们就一起去吃饭（then）如果拒绝，你就自己吃（catch）// Promise的基本使用 const promise = new Promise((resolve, reject) => { // 模拟异步操作 setTimeout(() => { const success = true; if (success) { resolve('操作成功！'); } else { reject('操作失败！'); } }, 1000); }); promise .then(result => console.log(result)) .catch(error => console.error(error));什么是axios？axios是一个基于Promise的HTTP客户端，专门用于处理网络请求。你可以把它理解为一个"升级版"的Ajax工具包。主要区别1. 使用方式Ajax：需要自己创建XMLHttpRequest对象，写起来比较麻烦const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.example.com/data'); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); } }; xhr.send();axios：使用起来简单直观axios.get('https://api.example.com/data') .then(response => { console.log(response.data); }) .catch(error => { console.error(error); });2. 功能特性Ajax：基础功能：发送请求、接收响应需要自己处理很多细节代码量较大// 发送POST请求 const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://api.example.com/data'); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { console.log(JSON.parse(xhr.responseText)); } else { console.error('请求失败'); } } }; xhr.send(JSON.stringify({ name: '张三', age: 20 }));axios：自动转换JSON数据支持Promise可以拦截请求和响应可以取消请求自动处理错误支持CSRF保护// 发送POST请求 axios.post('https://api.example.com/data', { name: '张三', age: 20 }) .then(response => { console.log(response.data); }) .catch(error => { console.error(error); }); // 请求拦截器 axios.interceptors.request.use(config => { // 在发送请求之前做些什么 config.headers['Authorization'] = 'Bearer token'; return config; }); // 响应拦截器 axios.interceptors.response.use(…

基于uniapp+vant的健身会员管理系统h5前端
type: item
date: 2025-04-17T01:52:00+08:00
description: 基于uni-app的健身会员管理系统前端技术分析项目背景本来是打算做一个会员管理的wx小程序，由于我开始前未弄清楚wx小程序原生语言和uniapp都分别支持什么组件，只知道uniapp可以开发小程序，直接就使用了vue3+vant4组件。做到最后要打包为微信小程序时傻了眼，成堆报错，查了查错误后才知道几乎都是vant4组件的错，根本用不了。查了查才知道vant weapp是专门用于小程序和app的组件，所以我就全部替换了，发现还是不行：页内跳转方法不对，底部导航栏导航方法也不对。。。于是索性不改了，还好备份过，h5就h5吧。业主后来想通过微信小程序来给他的会员发送到期请续费的通知（服务号通知）。但是经过我对这块狠狠地补习后，我发现目前的系统并不能做到这点，需要让会员们通过微信授权登录进来（但是感觉纯H5网站实现微信授权登录挺麻烦的），这样的话可以获取到他们的微信用户信息，就能通过服务号发送给每位授权登录的会员。我突然想到可不可以使用微信原生框架开发一个只做登录，登录的请求和返回都对应做好的这个h5网站，这样的话既能用微信官方登录接口，登录后的画面是这个h5网站，两全其美。但是哪有我想的这莫简单，微信虽然有一个<webview>可以做外部网站的显示容器，但是需要设置授权，所以行不通。后面我会单独发一篇文章，关于微信小程序开发方式以及我碰到的全部麻烦。最后我找到了一个公众号，专门转发这种通知，但有限制。所以最后到期通知只能发给业主自己，且没有会员登录的功能。后面会发一篇后端和数据库的实现以及如何部署。项目概述这是一个基于uni-app开发的健身会员管理系统，主要用于管理会员信息、课程进度以及发送到期提醒等功能。项目采用了Vue 3 + Vite的技术栈，整体架构清晰，代码组织规范。技术栈前端框架：Vue 3构建工具：ViteUI组件库：Vant weappHTTP请求：Axios跨端框架：uni-appAPI设计与实现1. 请求配置与拦截器项目使用了axios进行HTTP请求，并配置了完整的请求拦截和响应拦截机制。让我们来看看具体的实现：// 后端API配置 const backendAPI = { baseUrl: "/api", } // 创建axios实例 const instance = axios.create({ baseURL: backendAPI.baseUrl, timeout: 30000, headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, withCredentials: true })这段代码创建了一个axios实例，设置了基本的请求配置：baseURL: 设置API的基础路径timeout: 设置请求超时时间为30秒headers: 设置请求头，指定内容类型为JSONwithCredentials: 允许跨域请求携带cookieAPI路径配置详解在代码中出现的 /api 是一个API的基础路径（base URL），它表示：代理路径：在开发环境中，这个 /api 通常会被配置为代理路径比如当你在本地开发时，请求 /api/member/list 实际上会被代理到 http://localhost:3000/member/list 这样的实际后端地址实际作用：它作为所有API请求的前缀比如 getMemberList 方法实际请求的完整URL是 /api/member/list这样可以统一管理所有API的路径配置方式：在 vite.config.js 中通常会配置代理，类似这样：server: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true } } }实际部署时：在生产环境中，这个 /api 可能会指向实际的服务器地址比如 https://api.yourdomain.com这样设计的好处是：开发时可以使用代理避免跨域问题部署时只需要修改代理配置，不需要改代码统一管理所有API请求的路径前缀2. 请求拦截器instance.interceptors.request.use( config => { const token = uni.getStorageSync('token') if (token) { config.headers['Authorization'] = `Bearer ${token.trim()}` } return config }, error => { return Promise.reject(error) } )请求拦截器的主要作用是：在每次请求前自动添加token到请求头…