346 lines
7.2 KiB
Markdown
346 lines
7.2 KiB
Markdown
# 小程序头像上传优化说明
|
||
|
||
## 🔧 问题描述
|
||
|
||
**旧逻辑**:
|
||
- 小程序换头像时直接保存微信临时图片路径
|
||
- 临时路径会过期,导致头像无法显示
|
||
- 数据库存储的是微信的临时URL
|
||
|
||
**问题**:
|
||
- ❌ 微信临时图片有效期有限(通常几天后失效)
|
||
- ❌ 头像无法长期显示
|
||
- ❌ 用户体验差
|
||
|
||
---
|
||
|
||
## ✅ 解决方案
|
||
|
||
**新逻辑**:
|
||
1. 用户选择头像后,先上传图片到自己的服务器
|
||
2. 服务器保存图片到 `public/assets/avatars/` 目录
|
||
3. 返回永久可访问的URL
|
||
4. 将永久URL保存到数据库
|
||
|
||
**优势**:
|
||
- ✅ 图片永久保存在自己服务器
|
||
- ✅ 头像不会失效
|
||
- ✅ 完全可控
|
||
|
||
---
|
||
|
||
## 🔧 修改的文件
|
||
|
||
### 1. `miniprogram/pages/my/my.js`
|
||
|
||
**修改函数**: `onChooseAvatar()`
|
||
|
||
**旧逻辑**:
|
||
```javascript
|
||
// 直接使用临时路径
|
||
const avatarUrl = e.detail.avatarUrl
|
||
userInfo.avatar = avatarUrl
|
||
|
||
// 保存临时路径到数据库
|
||
await app.request('/api/user/update', {
|
||
data: { userId: userInfo.id, avatar: avatarUrl }
|
||
})
|
||
```
|
||
|
||
**新逻辑**:
|
||
```javascript
|
||
// 1. 上传到服务器
|
||
const uploadRes = await wx.uploadFile({
|
||
url: app.globalData.baseUrl + '/api/upload',
|
||
filePath: tempAvatarUrl,
|
||
name: 'file',
|
||
formData: { folder: 'avatars' }
|
||
})
|
||
|
||
// 2. 获取永久URL
|
||
const avatarUrl = app.globalData.baseUrl + uploadRes.data.url
|
||
|
||
// 3. 保存永久URL到数据库
|
||
await app.request('/api/user/update', {
|
||
data: { userId: userInfo.id, avatar: avatarUrl }
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
### 2. `miniprogram/pages/settings/settings.js`
|
||
|
||
**修改函数**: `getWechatAvatar()`
|
||
|
||
**功能**: 使用 `wx.getUserProfile` 获取微信头像
|
||
|
||
**修改内容**: 与 `my.js` 相同,先上传图片再保存URL
|
||
|
||
---
|
||
|
||
## 📁 服务器存储路径
|
||
|
||
### 图片保存位置
|
||
```
|
||
public/assets/avatars/
|
||
├── 1738756123456_abc123.jpg
|
||
├── 1738756234567_def456.png
|
||
└── ...
|
||
```
|
||
|
||
### 访问URL格式
|
||
```
|
||
https://soul.quwanzhi.com/assets/avatars/1738756123456_abc123.jpg
|
||
```
|
||
|
||
### 数据库存储
|
||
```javascript
|
||
// users 表
|
||
{
|
||
id: "user_123",
|
||
avatar: "https://soul.quwanzhi.com/assets/avatars/1738756123456_abc123.jpg"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 上传流程
|
||
|
||
### 完整流程图
|
||
|
||
```
|
||
用户点击更换头像
|
||
↓
|
||
微信弹出头像选择器(chooseAvatar / getUserProfile)
|
||
↓
|
||
获取临时图片路径(tempAvatarUrl)
|
||
↓
|
||
调用 wx.uploadFile 上传到服务器
|
||
↓
|
||
服务器保存图片到 public/assets/avatars/
|
||
↓
|
||
服务器返回永久URL
|
||
↓
|
||
更新本地 userInfo(app.globalData / storage)
|
||
↓
|
||
调用 /api/user/update 保存到数据库
|
||
↓
|
||
完成!
|
||
```
|
||
|
||
### 代码实现
|
||
|
||
```javascript
|
||
// 1. 获取临时头像
|
||
const tempAvatarUrl = e.detail.avatarUrl
|
||
|
||
// 2. 上传到服务器
|
||
const uploadRes = await new Promise((resolve, reject) => {
|
||
wx.uploadFile({
|
||
url: app.globalData.baseUrl + '/api/upload',
|
||
filePath: tempAvatarUrl,
|
||
name: 'file',
|
||
formData: {
|
||
folder: 'avatars' // 保存到 avatars 文件夹
|
||
},
|
||
success: (res) => {
|
||
const data = JSON.parse(res.data)
|
||
if (data.success) {
|
||
resolve(data) // { success: true, data: { url: '/assets/avatars/xxx.jpg' } }
|
||
} else {
|
||
reject(new Error(data.error))
|
||
}
|
||
},
|
||
fail: reject
|
||
})
|
||
})
|
||
|
||
// 3. 拼接完整URL
|
||
const avatarUrl = app.globalData.baseUrl + uploadRes.data.url
|
||
// 结果: https://soul.quwanzhi.com/assets/avatars/xxx.jpg
|
||
|
||
// 4. 保存到数据库
|
||
await app.request('/api/user/update', {
|
||
method: 'POST',
|
||
data: { userId: userInfo.id, avatar: avatarUrl }
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 错误处理
|
||
|
||
### 1. 上传失败
|
||
```javascript
|
||
try {
|
||
// ... 上传逻辑
|
||
} catch (e) {
|
||
wx.showToast({
|
||
title: e.message || '上传失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
```
|
||
|
||
### 2. 网络错误
|
||
- 自动重试机制(可选)
|
||
- 清晰的错误提示
|
||
|
||
### 3. 文件格式错误
|
||
- 服务器会验证文件类型
|
||
- 只允许 JPG、PNG、GIF、WebP、SVG
|
||
- 文件大小限制 5MB
|
||
|
||
---
|
||
|
||
## 📊 服务器API
|
||
|
||
### `/api/upload` - 图片上传接口
|
||
|
||
**请求方式**: POST (multipart/form-data)
|
||
|
||
**参数**:
|
||
- `file`: 图片文件
|
||
- `folder`: 保存文件夹(如 'avatars')
|
||
|
||
**返回**:
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"url": "/assets/avatars/1738756123456_abc123.jpg",
|
||
"fileName": "1738756123456_abc123.jpg",
|
||
"size": 45678,
|
||
"type": "image/jpeg"
|
||
}
|
||
}
|
||
```
|
||
|
||
**文件命名规则**:
|
||
```javascript
|
||
const timestamp = Date.now()
|
||
const randomStr = Math.random().toString(36).substring(2, 8)
|
||
const fileName = `${timestamp}_${randomStr}.${ext}`
|
||
// 例如: 1738756123456_abc123.jpg
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 测试清单
|
||
|
||
### 功能测试
|
||
- [ ] 在"我的"页面点击头像,选择图片后成功上传
|
||
- [ ] 上传后头像立即显示
|
||
- [ ] 刷新页面后头像依然正常显示
|
||
- [ ] 在设置页面使用"获取微信头像"功能正常
|
||
- [ ] 后台管理页面能正确显示用户头像
|
||
|
||
### 数据验证
|
||
- [ ] 数据库 `users.avatar` 字段保存的是完整URL
|
||
- [ ] URL格式: `https://soul.quwanzhi.com/assets/avatars/xxx.jpg`
|
||
- [ ] 不是微信临时路径(不包含 `weixin` 或 `tmp`)
|
||
|
||
### 文件验证
|
||
- [ ] 服务器 `public/assets/avatars/` 目录存在
|
||
- [ ] 上传的图片文件正常保存
|
||
- [ ] 文件可通过浏览器直接访问
|
||
|
||
---
|
||
|
||
## 🚀 部署步骤
|
||
|
||
### 1. 确保目录存在
|
||
```bash
|
||
# 在服务器上创建目录
|
||
mkdir -p /www/wwwroot/soul.quwanzhi.com/public/assets/avatars
|
||
chmod 755 /www/wwwroot/soul.quwanzhi.com/public/assets/avatars
|
||
```
|
||
|
||
### 2. 部署代码
|
||
```bash
|
||
# 本地构建
|
||
pnpm build
|
||
|
||
# 部署到服务器
|
||
python devlop.py
|
||
|
||
# 重启PM2
|
||
pm2 restart soul
|
||
```
|
||
|
||
### 3. 小程序代码上传
|
||
- 在微信开发者工具中上传代码
|
||
- 提交审核
|
||
- 发布新版本
|
||
|
||
---
|
||
|
||
## 📝 注意事项
|
||
|
||
### 1. 兼容性
|
||
- 旧版本用户的头像可能还是微信临时路径
|
||
- 建议提示用户重新上传头像
|
||
|
||
### 2. 存储空间
|
||
- 每个头像约 50-200KB
|
||
- 10000个用户约 0.5-2GB
|
||
- 定期清理无用头像(可选)
|
||
|
||
### 3. CDN优化(可选)
|
||
- 如果用户量大,考虑使用CDN加速
|
||
- 将 `public/assets/avatars/` 目录同步到CDN
|
||
|
||
### 4. 图片压缩(可选)
|
||
- 可以在上传时自动压缩图片
|
||
- 减少存储空间和加载时间
|
||
|
||
---
|
||
|
||
## 🔄 数据迁移(可选)
|
||
|
||
如果需要迁移旧数据(微信临时路径 → 永久URL):
|
||
|
||
### 方案1: 提示用户重新上传
|
||
```javascript
|
||
// 在小程序中检查头像URL
|
||
if (userInfo.avatar && userInfo.avatar.includes('weixin')) {
|
||
// 提示用户重新上传头像
|
||
wx.showModal({
|
||
title: '头像过期',
|
||
content: '请重新上传您的头像',
|
||
confirmText: '立即上传'
|
||
})
|
||
}
|
||
```
|
||
|
||
### 方案2: 自动下载并上传(服务器端)
|
||
```javascript
|
||
// 在服务器端批量处理
|
||
// 1. 查询所有微信临时路径的头像
|
||
// 2. 下载图片
|
||
// 3. 上传到自己服务器
|
||
// 4. 更新数据库
|
||
// (需要开发专门的迁移脚本)
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ 完成状态
|
||
|
||
- ✅ 修改 `my.js` 的 `onChooseAvatar()` 函数
|
||
- ✅ 修改 `settings.js` 的 `getWechatAvatar()` 函数
|
||
- ✅ 使用现有的 `/api/upload` 接口
|
||
- ✅ 添加错误处理和日志
|
||
- ✅ 创建说明文档
|
||
|
||
---
|
||
|
||
## 📚 相关文档
|
||
|
||
- `后台订单显示优化说明.md` - 后台显示头像相关
|
||
- `/api/upload` 接口文档
|
||
|
||
---
|
||
|
||
**优化完成!小程序头像将永久保存在自己的服务器上,不会再失效!**
|