281 lines
7.2 KiB
Markdown
281 lines
7.2 KiB
Markdown
# request.js 修改方案
|
||
|
||
## 1. 核心修改
|
||
|
||
### 1.1 修改 Content-Type
|
||
|
||
将 POST 请求的 Content-Type 从 `application/x-www-form-urlencoded` 改为 `application/json`。
|
||
|
||
### 1.2 修改位置
|
||
|
||
文件:`honey_box/common/request.js`
|
||
|
||
找到以下代码块(约第 130-140 行):
|
||
|
||
```javascript
|
||
if (method.toUpperCase() == 'POST') {
|
||
// ... 签名计算代码 ...
|
||
|
||
header = {
|
||
'content-type': 'application/x-www-form-urlencoded',
|
||
client: client,
|
||
token: token,
|
||
adid: uni.getStorageSync('_ad_id'),
|
||
clickid: uni.getStorageSync('_click_id')
|
||
}
|
||
}
|
||
```
|
||
|
||
### 1.3 修改后代码
|
||
|
||
```javascript
|
||
if (method.toUpperCase() == 'POST') {
|
||
// ... 签名计算代码保持不变 ...
|
||
|
||
header = {
|
||
'content-type': 'application/json', // 修改这一行
|
||
client: client,
|
||
token: token,
|
||
adid: uni.getStorageSync('_ad_id'),
|
||
clickid: uni.getStorageSync('_click_id')
|
||
}
|
||
}
|
||
```
|
||
|
||
## 2. 完整修改后的 request.js
|
||
|
||
```javascript
|
||
/**
|
||
* 网络请求工具类
|
||
* 封装统一的网络请求方法
|
||
*/
|
||
|
||
import EnvConfig from '@/common/env.js'
|
||
import md5 from 'js-md5'
|
||
|
||
import { apiWhiteList } from '@/common/config.js'
|
||
import RouterManager from '@/common/router.js'
|
||
import { platform } from '@/common/platform/PlatformFactory'
|
||
|
||
class RequestManager {
|
||
// 缓存对象
|
||
static cache = {
|
||
data: new Map(),
|
||
expireTime: 5 * 60 * 1000,
|
||
timestamps: new Map()
|
||
};
|
||
|
||
static isCacheValid(cacheKey) {
|
||
const now = Date.now();
|
||
if (this.cache.data.has(cacheKey)) {
|
||
const timestamp = this.cache.timestamps.get(cacheKey);
|
||
return now - timestamp < this.cache.expireTime;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static updateCache(cacheKey, data) {
|
||
this.cache.data.set(cacheKey, data);
|
||
this.cache.timestamps.set(cacheKey, Date.now());
|
||
}
|
||
|
||
static getCache(url, data = {}, showLoading = false) {
|
||
const cacheKey = url + JSON.stringify(data);
|
||
if (this.isCacheValid(cacheKey)) {
|
||
console.log(cacheKey + '缓存有效');
|
||
return Promise.resolve(this.cache.data.get(cacheKey));
|
||
}
|
||
return this.get(url, data, showLoading).then(result => {
|
||
this.updateCache(cacheKey, result);
|
||
return result;
|
||
});
|
||
}
|
||
|
||
static isUrlInWhitelist(url) {
|
||
return apiWhiteList.some(whiteItem => url.indexOf(whiteItem) > -1);
|
||
}
|
||
|
||
static generateNonce() {
|
||
return md5(Date.now() + Math.random().toString(36).substring(2, 15));
|
||
}
|
||
|
||
static request(param, backpage, backtype) {
|
||
return new Promise((resolve, reject) => {
|
||
if (!param || typeof param !== 'object') {
|
||
reject(new Error('请求参数错误'))
|
||
return
|
||
}
|
||
|
||
uni.getNetworkType({
|
||
success: function (res) {
|
||
if (res.networkType == 'none') {
|
||
uni.showToast({
|
||
title: '网络连接异常,请检查网络',
|
||
icon: 'none'
|
||
})
|
||
reject(new Error('网络连接异常'))
|
||
return
|
||
}
|
||
}
|
||
})
|
||
|
||
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
|
||
const apiBaseUrl = EnvConfig.apiBaseUrl
|
||
|
||
let requestUrl = ''
|
||
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||
requestUrl = url
|
||
} else {
|
||
const baseUrlWithSlash = apiBaseUrl.endsWith('/') ? apiBaseUrl : apiBaseUrl + '/'
|
||
const path = url.startsWith('/') ? url.substring(1) : url
|
||
requestUrl = baseUrlWithSlash + path
|
||
}
|
||
|
||
const hostRegex = /^(?:https?:\/\/)?([^\/]+)/i
|
||
const matches = requestUrl.match(hostRegex)
|
||
const host = matches && matches[1] ? matches[1] : 'localhost'
|
||
|
||
let header = {}
|
||
|
||
// 添加签名参数
|
||
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 格式的请求头
|
||
header = {
|
||
'content-type': 'application/json', // 关键修改:统一使用 JSON
|
||
client: client,
|
||
token: token,
|
||
adid: uni.getStorageSync('_ad_id'),
|
||
clickid: uni.getStorageSync('_click_id')
|
||
}
|
||
|
||
if (!Loading) {
|
||
uni.showLoading({
|
||
title: '加载中...'
|
||
})
|
||
}
|
||
|
||
uni.request({
|
||
url: requestUrl,
|
||
method: method.toUpperCase(),
|
||
header: header,
|
||
data: data,
|
||
success: res => {
|
||
// ... 响应处理代码保持不变 ...
|
||
},
|
||
fail: e => {
|
||
console.error('网络请求失败:', e)
|
||
uni.showToast({
|
||
title: e.errMsg || '请求失败',
|
||
icon: 'none'
|
||
})
|
||
typeof param.fail == 'function' && param.fail(e)
|
||
reject(e)
|
||
},
|
||
complete: () => {
|
||
uni.hideLoading()
|
||
typeof param.complete == 'function' && param.complete()
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
static get(url, data = {}, showLoading = true) {
|
||
return this.request({
|
||
url,
|
||
data,
|
||
method: 'GET',
|
||
Loading: !showLoading
|
||
})
|
||
}
|
||
|
||
static post(url, data = {}, showLoading = true) {
|
||
return this.request({
|
||
url,
|
||
data,
|
||
method: 'POST',
|
||
Loading: !showLoading
|
||
})
|
||
}
|
||
}
|
||
|
||
export default RequestManager;
|
||
```
|
||
|
||
## 3. 签名机制说明
|
||
|
||
修改 Content-Type 后,签名机制保持不变:
|
||
|
||
1. 参数按键名排序
|
||
2. 拼接为 `key=value&` 格式
|
||
3. 添加密钥 `host + timestamp`
|
||
4. MD5 加密生成签名
|
||
|
||
后端需要确保能正确解析 JSON 格式的请求体并验证签名。
|
||
|
||
## 4. 后端签名验证
|
||
|
||
C# 后端需要从 JSON 请求体中提取参数进行签名验证:
|
||
|
||
```csharp
|
||
// 示例:签名验证中间件
|
||
public class SignatureValidationMiddleware
|
||
{
|
||
public async Task InvokeAsync(HttpContext context)
|
||
{
|
||
if (context.Request.Method == "POST" &&
|
||
context.Request.ContentType?.Contains("application/json") == true)
|
||
{
|
||
// 读取请求体
|
||
context.Request.EnableBuffering();
|
||
var body = await new StreamReader(context.Request.Body).ReadToEndAsync();
|
||
context.Request.Body.Position = 0;
|
||
|
||
// 解析 JSON 并验证签名
|
||
var data = JsonSerializer.Deserialize<Dictionary<string, object>>(body);
|
||
// ... 签名验证逻辑 ...
|
||
}
|
||
|
||
await _next(context);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 5. 测试验证
|
||
|
||
修改后需要测试以下场景:
|
||
|
||
1. **登录接口**:`POST /api/login`
|
||
2. **获取用户信息**:`POST /api/user`
|
||
3. **商品列表**:`POST /api/goods_list`
|
||
4. **创建订单**:`POST /api/orderbuy`
|
||
|
||
确保签名验证通过,数据正确传递。
|