7.2 KiB
7.2 KiB
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 行):
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 修改后代码
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
/**
* 网络请求工具类
* 封装统一的网络请求方法
*/
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 后,签名机制保持不变:
- 参数按键名排序
- 拼接为
key=value&格式 - 添加密钥
host + timestamp - MD5 加密生成签名
后端需要确保能正确解析 JSON 格式的请求体并验证签名。
4. 后端签名验证
C# 后端需要从 JSON 请求体中提取参数进行签名验证:
// 示例:签名验证中间件
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. 测试验证
修改后需要测试以下场景:
- 登录接口:
POST /api/login - 获取用户信息:
POST /api/user - 商品列表:
POST /api/goods_list - 创建订单:
POST /api/orderbuy
确保签名验证通过,数据正确传递。