# 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>(body); // ... 签名验证逻辑 ... } await _next(context); } } ``` ## 5. 测试验证 修改后需要测试以下场景: 1. **登录接口**:`POST /api/login` 2. **获取用户信息**:`POST /api/user` 3. **商品列表**:`POST /api/goods_list` 4. **创建订单**:`POST /api/orderbuy` 确保签名验证通过,数据正确传递。