HaniBlindBox/docs/前端适配调整/request.js修改方案.md
2026-01-03 15:21:36 +08:00

281 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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`
确保签名验证通过,数据正确传递。