302 lines
8.4 KiB
Markdown
302 lines
8.4 KiB
Markdown
# 前端API适配方案
|
||
|
||
## 1. 问题概述
|
||
|
||
在将后端从 PHP (ThinkPHP 6.0) 迁移到 .NET 10 的过程中,前端 UniApp 项目需要进行适配调整。主要问题包括:
|
||
|
||
1. **请求格式不兼容**:前端使用 `application/x-www-form-urlencoded`,后端期望 `application/json`
|
||
2. **请求方式不一致**:同一接口在不同页面使用不同的请求方式(GET/POST)
|
||
3. **部分接口遗漏**:如 `/api/goods_list`、`/api/coupon` 等接口未正确对接
|
||
|
||
## 2. 当前前端请求机制分析
|
||
|
||
### 2.1 请求封装 (`honey_box/common/request.js`)
|
||
|
||
当前请求封装的关键特点:
|
||
|
||
```javascript
|
||
// POST 请求使用 form-urlencoded
|
||
if (method.toUpperCase() == 'POST') {
|
||
header = {
|
||
'content-type': 'application/x-www-form-urlencoded',
|
||
// ...
|
||
}
|
||
} else {
|
||
// GET 请求使用 json
|
||
header = {
|
||
'content-type': 'application/json',
|
||
// ...
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2.2 签名机制
|
||
|
||
前端对所有请求都添加了签名参数:
|
||
- `timestamp`: 时间戳
|
||
- `nonce`: 随机字符串
|
||
- `sign`: MD5签名
|
||
|
||
签名算法:
|
||
1. 参数按键名排序
|
||
2. 拼接为 `key=value&` 格式
|
||
3. 添加密钥 `host + timestamp`
|
||
4. MD5 加密
|
||
|
||
## 3. 适配方案
|
||
|
||
### 方案一:前端统一改为 JSON 格式(推荐)
|
||
|
||
#### 3.1 修改 `request.js`
|
||
|
||
将 POST 请求的 Content-Type 改为 `application/json`:
|
||
|
||
```javascript
|
||
// 修改前
|
||
if (method.toUpperCase() == 'POST') {
|
||
header = {
|
||
'content-type': 'application/x-www-form-urlencoded',
|
||
// ...
|
||
}
|
||
}
|
||
|
||
// 修改后
|
||
if (method.toUpperCase() == 'POST') {
|
||
header = {
|
||
'content-type': 'application/json',
|
||
// ...
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3.2 完整修改示例
|
||
|
||
```javascript
|
||
static request(param, backpage, backtype) {
|
||
return new Promise((resolve, reject) => {
|
||
// ... 参数检查代码 ...
|
||
|
||
const url = param.url || ''
|
||
const method = param.method || 'POST'
|
||
const data = param.data || {}
|
||
const Loading = param.Loading || false
|
||
const token = uni.getStorageSync('token')
|
||
let client = platform.code
|
||
|
||
// ... URL 拼接代码 ...
|
||
|
||
// 添加签名参数
|
||
data.timestamp = Math.floor(Date.now() / 1000)
|
||
data.nonce = RequestManager.generateNonce()
|
||
|
||
// 生成签名
|
||
const sortedParams = {}
|
||
Object.keys(data).sort().forEach(key => {
|
||
sortedParams[key] = data[key]
|
||
})
|
||
|
||
let signStr = ''
|
||
for (const key in sortedParams) {
|
||
if (typeof sortedParams[key] === 'object') {
|
||
signStr += key + '=' + JSON.stringify(sortedParams[key]) + '&'
|
||
} else {
|
||
signStr += key + '=' + sortedParams[key] + '&'
|
||
}
|
||
}
|
||
|
||
const timestamp = data.timestamp
|
||
const appSecret = host + timestamp
|
||
signStr = signStr.substring(0, signStr.length - 1) + appSecret
|
||
const sign = md5(signStr)
|
||
data.sign = sign
|
||
|
||
// 统一使用 JSON 格式
|
||
const header = {
|
||
'content-type': 'application/json',
|
||
client: client,
|
||
token: token,
|
||
adid: uni.getStorageSync('_ad_id'),
|
||
clickid: uni.getStorageSync('_click_id')
|
||
}
|
||
|
||
// ... 发起请求代码 ...
|
||
})
|
||
}
|
||
```
|
||
|
||
### 方案二:后端兼容 form-urlencoded(备选)
|
||
|
||
如果不想修改前端,可以在后端添加中间件支持 form-urlencoded:
|
||
|
||
```csharp
|
||
// 在 Program.cs 中添加
|
||
builder.Services.AddControllers()
|
||
.AddNewtonsoftJson()
|
||
.ConfigureApiBehaviorOptions(options =>
|
||
{
|
||
// 支持 form-urlencoded
|
||
});
|
||
```
|
||
|
||
但这种方案不推荐,因为:
|
||
1. 增加后端复杂度
|
||
2. 不符合 RESTful API 规范
|
||
3. 后续维护困难
|
||
|
||
## 4. 接口请求方式统一
|
||
|
||
### 4.1 当前接口请求方式对照表
|
||
|
||
| 接口路径 | PHP 旧版 | C# 新版 | 前端当前使用 | 需要调整 |
|
||
|---------|---------|---------|-------------|---------|
|
||
| `/api/config` | GET/POST | GET | GET | ✅ 无需调整 |
|
||
| `/api/getPlatformConfig` | GET/POST | GET | GET | ✅ 无需调整 |
|
||
| `/api/getAdvert` | GET/POST | GET/POST | GET | ✅ 无需调整 |
|
||
| `/api/getDanye` | GET/POST | GET | GET | ✅ 无需调整 |
|
||
| `/api/goods_list` | POST | POST | POST | ✅ 无需调整 |
|
||
| `/api/goods_detail` | POST | POST | POST | ✅ 无需调整 |
|
||
| `/api/user` | POST | POST | GET | ⚠️ 需要调整 |
|
||
| `/api/login` | POST | POST | POST | ✅ 无需调整 |
|
||
| `/api/mobileLogin` | POST | POST | POST | ✅ 无需调整 |
|
||
| `/api/coupon_list` | POST | POST | POST | ✅ 无需调整 |
|
||
| `/api/order_list` | POST | POST | POST | ✅ 无需调整 |
|
||
|
||
### 4.2 需要调整的接口
|
||
|
||
#### `/api/user` - 获取用户信息
|
||
|
||
**问题**:前端 `user.js` 使用 GET 请求,后端期望 POST
|
||
|
||
```javascript
|
||
// honey_box/common/server/user.js
|
||
// 修改前
|
||
export const getUserInfo = async () => {
|
||
const res = await RequestManager.get('/userInfo');
|
||
// ...
|
||
}
|
||
|
||
// 修改后
|
||
export const getUserInfo = async () => {
|
||
const res = await RequestManager.post('/user');
|
||
// ...
|
||
}
|
||
```
|
||
|
||
## 5. 遗漏接口清单
|
||
|
||
根据分析,以下接口可能存在问题:
|
||
|
||
### 5.1 商品相关
|
||
|
||
| 接口 | 状态 | 说明 |
|
||
|-----|------|-----|
|
||
| `POST /api/goods_list` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
| `POST /api/goods_detail` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
|
||
### 5.2 优惠券相关
|
||
|
||
| 接口 | 状态 | 说明 |
|
||
|-----|------|-----|
|
||
| `POST /api/coupon_list` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
| `POST /api/coupon_detail` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
| `POST /api/coupon_ling` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
|
||
### 5.3 订单相关
|
||
|
||
| 接口 | 状态 | 说明 |
|
||
|-----|------|-----|
|
||
| `POST /api/ordermoney` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
| `POST /api/orderbuy` | ⚠️ 需检查 | 前端请求格式需改为 JSON |
|
||
|
||
## 6. 实施步骤
|
||
|
||
### 第一阶段:修改请求封装(核心)
|
||
|
||
1. 修改 `honey_box/common/request.js`
|
||
2. 将 POST 请求的 Content-Type 改为 `application/json`
|
||
3. 测试基础接口(登录、配置获取)
|
||
|
||
### 第二阶段:统一接口调用方式
|
||
|
||
1. 检查 `honey_box/common/server/` 下所有接口文件
|
||
2. 统一使用正确的请求方式(GET/POST)
|
||
3. 确保接口路径与后端一致
|
||
|
||
### 第三阶段:逐模块测试
|
||
|
||
1. 用户认证模块(登录、注册、绑定手机号)
|
||
2. 商品模块(列表、详情、奖品)
|
||
3. 订单模块(下单、支付、抽奖)
|
||
4. 仓库模块(回收、发货)
|
||
5. 福利模块(签到、任务)
|
||
|
||
## 7. 代码修改清单
|
||
|
||
### 7.1 `honey_box/common/request.js`
|
||
|
||
```diff
|
||
- header = {
|
||
- 'content-type': 'application/x-www-form-urlencoded',
|
||
- client: client,
|
||
- token: token,
|
||
- adid: uni.getStorageSync('_ad_id'),
|
||
- clickid: uni.getStorageSync('_click_id')
|
||
- }
|
||
+ header = {
|
||
+ 'content-type': 'application/json',
|
||
+ client: client,
|
||
+ token: token,
|
||
+ adid: uni.getStorageSync('_ad_id'),
|
||
+ clickid: uni.getStorageSync('_click_id')
|
||
+ }
|
||
```
|
||
|
||
### 7.2 `honey_box/common/server/user.js`
|
||
|
||
```diff
|
||
export const getUserInfo = async () => {
|
||
- const res = await RequestManager.get('/userInfo');
|
||
+ const res = await RequestManager.post('/user');
|
||
if (res.status == 1) {
|
||
res.data.money = common.removeTrailingZeros(res.data.money);
|
||
res.data.integral = common.removeTrailingZeros(res.data.integral);
|
||
res.data.money2 = common.removeTrailingZeros(res.data.money2);
|
||
return res.data;
|
||
} else {
|
||
return null;
|
||
}
|
||
};
|
||
```
|
||
|
||
## 8. 测试验证
|
||
|
||
### 8.1 测试用例
|
||
|
||
| 测试项 | 预期结果 | 实际结果 |
|
||
|-------|---------|---------|
|
||
| 获取系统配置 | 返回配置数据 | |
|
||
| 手机号登录 | 返回 token | |
|
||
| 获取用户信息 | 返回用户数据 | |
|
||
| 获取商品列表 | 返回商品分页数据 | |
|
||
| 获取优惠券列表 | 返回优惠券数据 | |
|
||
| 创建订单 | 返回订单信息 | |
|
||
|
||
### 8.2 调试工具
|
||
|
||
前端已集成 eruda 调试工具,可在开发环境查看网络请求详情。
|
||
|
||
## 9. 注意事项
|
||
|
||
1. **签名机制保持不变**:修改 Content-Type 不影响签名计算
|
||
2. **Token 传递方式不变**:继续通过 header 传递
|
||
3. **响应格式不变**:后端返回格式与 PHP 版本保持一致
|
||
4. **错误码保持一致**:status 码含义不变
|
||
|
||
## 10. 回滚方案
|
||
|
||
如果修改后出现问题,可以:
|
||
|
||
1. 恢复 `request.js` 中的 Content-Type 为 `application/x-www-form-urlencoded`
|
||
2. 在后端添加 form-urlencoded 支持中间件
|
||
3. 逐步排查问题接口
|