如何自动判断Request.QueryString参数的编码格式

本文介绍了一种通过分析URL中的百分号数量来判断其编码格式(GB2312或UTF-8)的方法,并提供了具体的C#实现代码。通过对输入字符串中特定序列的计数,可以确定正确的解码方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 帖子地址:http://topic.youkuaiyun.com/u/20091105/15/0d54b7b2-38fe-4cdf-ae1b-5a1f07c26ea0.html?seed=1186869228&r=60954435#r_60954435

 

解决办法:

 

input 为 context.Request.ServerVariables["QUERY_STRING"]

 

        private static int GetInCount(string input, string fstring)
        {
            return input.Length - input.Replace(fstring, String.Empty).Length;
        }
        private static string UrlDecode(string input)
        {
            int _c = GetInCount(input, "%");
            if (_c > 1)
            {
                if (_c % 3 != 0)
                {
                    return System.Web.HttpUtility.UrlDecode(input, System.Text.Encoding.Default);
                }
                else
                {
                    if (_c > 3 && input.Length > input.IndexOf("%") + 9)
                    {
                        string ckst = input.Substring(input.IndexOf("%"), 9);
                        string ck = System.Web.HttpUtility.UrlDecode(ckst, System.Text.Encoding.UTF8);
                        if (ck.Length == 1)
                        {
                            return System.Web.HttpUtility.UrlDecode(input, System.Text.Encoding.UTF8);
                        }
                        else
                        {
                            return System.Web.HttpUtility.UrlDecode(input, System.Text.Encoding.Default);
                        }
                    }
                    else
                    {
                        return System.Web.HttpUtility.UrlDecode(input, System.Text.Encoding.UTF8);
                    }
                }
            }
            return input;
        }

 

 

原理:

GB2312 为 一个汉字2组编码

UTF8 为 一个汉字 为3组编码

 

我取 三组编码出来 使用 UTF8转 如果是 UTF8 格式的 应该是一个汉字,如果是GB2312 应该就是2个字了

 

SO ^_^ 解决

 

<think>我们参考用户提供的引用内容,以及用户之前的问题(关于GET请求携带参数),来封装一个更完善的HTTP请求方法。 目标:封装GET和POST请求,支持统一添加请求头(如token),统一处理加载状态,统一处理错误提示,返回Promise便于异步处理。 改进点: 1. 将公共配置提取(如baseUrl、请求头) 2. 统一处理请求参数:GET请求的参数应该拼接到URL上(注意数组等特殊情况的处理),POST请求参数放在data中 3. 统一处理响应:根据业务逻辑判断请求成功与否(例如状态码为200,且自定义的业务状态码成功) 4. 统一错误处理(网络错误、服务器错误等) 5. 使用拦截器(可选)或封装函数来处理公共逻辑 但是,注意引用[1]和[2]中的封装方式,它们都是直接封装成函数,没有使用拦截器。我们这里也采用函数封装的方式。 步骤: 1. 创建http.js文件,封装request函数(支持GET和POST) 2. 设置baseUrl 3. 从本地存储获取token,并设置到请求头 4. 显示加载中(uni.showLoading) 5. 对于GET请求,将参数拼接到URL(注意:需要处理数组、特殊字符等,但这里我们先做简单处理,使用JSON.stringify会导致问题,所以一般只支持基本类型) 如果遇到数组,我们可以使用qs库(需要安装)或者自己处理成重复的key,但为了简单,我们先不处理数组,提示用户参数不要用数组。 6. 返回Promise,在请求成功时resolve,失败时reject 7. 在成功响应中,可以判断业务状态码(如res.data.code),如果不是成功状态,可以统一提示错误并reject(这里根据业务来,有的业务错误不提示,由调用方处理) 8. 隐藏加载中(在finally中隐藏?但uni.request的success和fail回调中都需要隐藏,所以我们在两个回调中都调用uni.hideLoading) 注意:引用[1]中把token直接拼接在URL上,这样不安全,建议放在header中。 我们参考引用[2]的方式,将token放在请求头。 设计: 请求配置: method: 方法(必须) url: 相对路径(必须) data: 参数(可选) headers: 额外的请求头(可选) 封装两个函数:get和post,它们都调用一个公共的request函数。 代码结构: http.js ======= const baseUrl = 'http://api.example.com/'; // 公共请求函数 function request(method, url, data, customHeader = {}) { return new Promise((resolve, reject) => { // 显示加载中 uni.showLoading({ title: '加载中...' }); // 获取token const token = uni.getStorageSync('token') || ''; // 设置请求头 const header = { 'Content-Type': method === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded', 'Authorization': token ? `Bearer ${token}` : '', ...customHeader }; // 处理GET请求的URL参数 let requestUrl = baseUrl + url; if (method === 'GET' && data) { // 将参数对象转换为查询字符串 const params = Object.keys(data).map(key => { // 注意:这里只处理基本类型,数组和对象需要调用方自己处理成字符串,或者我们使用第三方库如qs return `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`; }).join('&'); requestUrl += `?${params}`; } uni.request({ url: requestUrl, method: method, data: method !== 'GET' ? data : {}, header: header, success: (res) => { // 隐藏加载 uni.hideLoading(); // 这里可以处理HTTP状态码,比如200-299之间认为成功 if (res.statusCode >= 200 && res.statusCode < 300) { // 如果业务状态码也是成功的,则resolve,否则根据业务处理 // 假设业务返回的数据中有一个code字段,0表示成功 if (res.data.code === 0) { resolve(res.data); } else { // 业务错误,可以提示 uni.showToast({ title: res.data.msg || '业务错误', icon: 'none' }); reject(res.data); } } else { // HTTP状态码错误 uni.showToast({ title: `请求错误:${res.statusCode}`, icon: 'none' }); reject(res); } }, fail: (err) => { uni.hideLoading(); uni.showToast({ title: '网络错误,请稍后重试', icon: 'none' }); reject(err); } }); }); } // 封装get方法 function get(url, data, header) { return request('GET', url, data, header); } // 封装post方法 function post(url, data, header) { return request('POST', url, data, header); } export default { get, post }; 但是,注意:上述代码中,对于GET请求,我们手动拼接了URL,而POST请求的Content-Type设置为application/json,并且数据以JSON格式发送。 问题: 1. 对于GET请求,如果参数是数组怎么办?比如:{ ids: [1,2,3] },我们希望转换成 ?ids=1&ids=2&ids=3 或者 ?ids=1,2,3 这里我们不做复杂处理,因为UniApp的uni.request在GET请求中,如果传入data,它实际上会自动拼接到URL上,但是它的处理方式是将数组转成逗号分隔的字符串(ids=1,2,3)。所以我们可以不用手动拼接,直接使用uni.request的data参数,让系统自己处理。 因此,改进:我们不在GET请求中手动拼接URL,而是直接使用uni.request的data参数,因为uni.request内部会处理。 修改request函数: if (method === 'GET') { // 直接使用uni.request的data,它会自动拼接到URL // 所以不需要修改url requestUrl = baseUrl + url; } else { requestUrl = baseUrl + url; } 然后,在uni.request中,data参数根据方法传入: data: method === 'GET' ? data : data, 但是注意:这样GET请求中,数组参数会被转成逗号分隔,可能不符合后端要求。如果后端要求不同的格式,需要自行处理。 所以,我们保留手动拼接的方式,但是提供一个参数处理函数,这里我们为了简单,使用内置的URLSearchParams(注意兼容性)或者自己写一个序列化函数。 由于UniApp运行环境包括小程序,而小程序不支持URLSearchParams,所以我们自己写一个简单的: function serialize(data) { if (!data) return ''; return Object.keys(data).map(key => { const value = data[key]; // 如果是数组,则转换成 key=value1&key=value2 的形式 if (Array.isArray(value)) { return value.map(v => `${encodeURIComponent(key)}=${encodeURIComponent(v)}`).join('&'); } return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; }).join('&'); } 然后在GET请求中: if (method === 'GET' && data) { const queryString = serialize(data); if (queryString) { requestUrl += (requestUrl.includes('?') ? '&' : '?') + queryString; } } 但是这样处理数组会变成重复的key,例如:ids=1&ids=2&ids=3,这是后端常用的方式。 考虑到这个序列化函数可能不够通用,我们也可以引入qs库(需要安装),但为了减少依赖,我们可以根据项目需要选择。 这里,我们假设项目暂时不需要处理数组,那么我们可以先不处理,或者使用简单的序列化(只处理基本类型和数组,且数组转换成重复key)。 我们写一个简单的序列化函数(支持数组转重复key,对象转JSON字符串): function serialize(data) { const parts = []; for (let key in data) { if (data.hasOwnProperty(key)) { const value = data[key]; if (value === null || typeof value === 'undefined') { continue; } if (Array.isArray(value)) { value.forEach(v => { parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(v)}`); }); } else if (typeof value === 'object') { parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value))}`); } else { parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`); } } } return parts.join('&'); } 然后使用这个函数来序列化GET参数。 但是,如果参数是嵌套对象,我们这里将对象转成JSON字符串,需要后端配合解析。 根据需求,我们这里先采用简单方式,因为大多数情况参数是简单的。 综合以上,我们给出一个封装示例,并加上注释。 注意:用户提供的引用中,有在URL上直接拼接name和toker,我们这里改为从header中传递token。 最终代码示例(http.js):</think>在 UniApp 中封装 HTTP 请求方法可以提高代码复用性和可维护性。以下是一个完整的封装方案,结合了 GET 和 POST 请求的统一处理: ### 完整封装方案 (http.js) ```javascript // 配置文件 config.js const config = { baseUrl: 'https://api.example.com', // 基础API地址 timeout: 10000, // 请求超时时间 tokenKey: 'auth_token' // 本地存储的token键名 } export default config; ``` ```javascript // 封装的请求方法 http.js import config from './config.js'; class HttpRequest { constructor() { this.baseUrl = config.baseUrl; this.timeout = config.timeout; } // 核心请求方法 request(method, endpoint, data = {}) { return new Promise((resolve, reject) => { // 显示加载提示 uni.showLoading({ title: '加载中...', mask: true }); // 获取本地存储的token const token = uni.getStorageSync(config.tokenKey) || ''; // 请求配置 const requestConfig = { url: `${this.baseUrl}${endpoint}`, method: method.toUpperCase(), data: method.toUpperCase() === 'GET' ? {} : data, timeout: this.timeout, header: { 'Content-Type': 'application/json', 'Authorization': token ? `Bearer ${token}` : '' }, success: (res) => this._handleSuccess(res, resolve, reject), fail: (err) => this._handleFail(err, reject) }; // GET请求特殊处理 if (method.toUpperCase() === 'GET' && Object.keys(data).length) { const queryString = this._serializeParams(data); requestConfig.url += `?${queryString}`; } uni.request(requestConfig); }); } // 处理成功响应 _handleSuccess(res, resolve, reject) { uni.hideLoading(); // 统一处理HTTP状态码 if (res.statusCode >= 200 && res.statusCode < 300) { // 根据业务状态码进一步处理 if (res.data.code === 0) { // 假设0表示成功 resolve(res.data); } else { this._showErrorToast(res.data.message || '业务逻辑错误'); reject(res.data); } } else { this._showErrorToast(`请求失败: ${res.statusCode}`); reject(res); } } // 处理失败请求 _handleFail(err, reject) { uni.hideLoading(); this._showErrorToast('网络连接失败'); reject(err); } // 序列化GET参数 _serializeParams(params) { return Object.keys(params) .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) .join('&'); } // 显示错误提示 _showErrorToast(message) { uni.showToast({ title: message, icon: 'none', duration: 2000 }); } // GET请求快捷方法 get(endpoint, params = {}) { return this.request('GET', endpoint, params); } // POST请求快捷方法 post(endpoint, data = {}) { return this.request('POST', endpoint, data); } } const http = new HttpRequest(); export default http; ``` ### 使用示例 ```javascript import http from '@/utils/http.js'; // GET请求示例 export const fetchProducts = (category, page = 1) => { return http.get('/products', { category, page, page_size: 10 }); }; // POST请求示例 export const login = (username, password) => { return http.post('/auth/login', { username, password }); }; // 在页面中使用 async function getUserData() { try { const response = await fetchProducts('electronics', 1); console.log('产品列表:', response.data); } catch (error) { console.error('获取产品失败:', error); } } ``` ### 封装特点与优势 1. **统一配置管理** - 基础 URL 和超时时间统一配置 - Token 自动从本地存储获取并添加到请求头[^1] 2. **自动化处理** - GET 参数自动序列化并拼接到 URL - 统一处理加载状态和错误提示 - 自动隐藏加载动画 3. **错误处理机制** - 区分网络错误和业务错误 - 统一错误提示方式 - 支持自定义错误消息 4. **安全机制** - Token 通过 Authorization 头传递而非 URL 参数[^1] - 参数自动 URL 编码防止注入攻击 5. **扩展性** - 可轻松添加 PUT、DELETE 等方法 - 支持添加请求拦截器和响应拦截器 ### 最佳实践建议 1. **敏感参数处理** ```javascript // 安全示例:敏感数据放在POST请求体中 http.post('/payment', { card_number: encrypt(cardNumber), // 加密处理 amount: 100 }); ``` 2. **添加请求拦截器** ```javascript // 在构造函数中添加 constructor() { // ... uni.addInterceptor('request', { invoke: (args) => { // 统一添加时间戳 if (args.method === 'GET') { args.url += args.url.includes('?') ? '&' : '?'; args.url += `_t=${Date.now()}`; } } }); } ``` 3. **处理复杂数据结构** ```javascript // 数组参数处理 get('/search', { ids: [1, 2, 3], // 转换为: ids=1&ids=2&ids=3 }); // 嵌套对象处理 post('/filter', { filters: JSON.stringify({ price: { min: 100, max: 500 }, brands: ['A', 'B'] }) }); ``` 4. **超长参数处理** ```javascript // 当GET参数过长时自动转为POST if (queryString.length > 1500) { console.warn('GET参数过长,自动转为POST'); return this.request('POST', endpoint, params); } ``` 此封装方案提供了统一的请求处理流程,支持 GET/POST 方法,包含错误处理、加载状态管理、安全机制等完整功能,可直接集成到 UniApp 项目中[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值