一起谈.NET技术,参数编码 完全解决方案

参数编码规范

一.摘要

我们经常要在页面传递中文数据,但是往往被文字编码所困惑.有时不了解到底是浏览器编码问题还是服务器编码问题.本文分析了互联网传递数据的编码原理, 并且提出了完善易用的解决方案.

二.原则

避免在get或者post参数时直接传递中文字符.中文参数需要经过编码后再传递.服务器端要使用相同的编码格式进行解码

三.错误观点

1.很多程序员认为url中可以传递中文. 
url中并不能携带中文参数.如果我们在浏览器中输入"http://localhost/?a=中文",感觉上我们在url中带了中文,实际上当按下回车键后,浏览器自动将其中的"中文"汉字进行编码后传递给服务器.

2.当获取中文参数产生了乱码时, 往往首先检查服务器端程序的编码格式.
很多人认为url可以传递中文,不知道浏览器有自动编码的行为, 所以单纯的认为问题出在服务器端.其实即使在服务器端找到了正确的编码格式,我们也不应该轻易地改变服务器的默认编码格式. 

3.传递参数前编码,使用Request对象获取参数时解码
很多的程序员认为认为,传递参数时我们使用UrlEncode等方式编码, 在接收时应该使用UrlDecode解码.这是常见的错误请大家一定要注意,使用默认的Request.QueryString和Request.Form时已经自动执行了一次解码,使用的解码格式是服务器端设置的默认编码格式.

四.原因

传递中文字符时,自动的编码解码格式和浏览器与服务器的设置有关.

测试Firefox3和IE6的Get方式发送中文参数, Firefox默认使用UTF-8格式编码中文参数, 而IE6即使在高级设置中设置了"总是以 UTF-8 发送URL", 仍然自动使用GB2312编码中文参数.

对于服务器端我们可以自由的控制解码的格式.但是往往是通过更改服务器配置进行全局的统一设置.比如对于ASP.NET程序.可以在Web.Config中设置服务器段的编码和解码格式:

<globalization culture="zh-CN" uiCulture="zh-CN" requestEncoding="UTF-8" responseEncoding="gb2312" />

但是我们没法控制浏览器端行为.用户可能使用不同的浏览器.

五.解决方案

1.统一默认的编码格式

(1)设置服务器端的编码格式为UTF-8

(2)传递参数全部进行编码,.服务器端(C#)使用Server.UrlEncode方法,客户端(javascript)使用encodeURIComponent方法.

说明:

客户端的javascript函数encodeURIComponent只能使用UTF-8编码格式. 所以需要设置服务器端request和response都为UTF-8.

缺陷是如果某些合作伙伴必须传递其他的编码格式的参数, 则服务器端或获取到乱码.此方案实现简单,适合大部分场景.

2.通过编码参数指定编码格式

为了解决可能存在的无法统一编码格式的问题, 我们使用一个参数"encoding"来显示的指定编码格式.encoding参数需要在所有的请求中传递,无论是get还是post.

(1)对于javascript客户端编码而言, 仍然使用encodeURIComponent方法编码, 此时指定encoding参数的值为"UTF-8".

(2)对于传入给服务器端的其他编码格式, 比如GB2312, 我们不能使用默认的Request.Form或者QueryString方法进行编码.因为服务器端的编码格式可能设置为了UTF-8.此时使用Request.Form或者QueryString会自动使用服务器端指定的编码格式进行解码. 所以需要使用下面的方法自己处理请求,获取参数:


/// <summary>
/// 根据指定的编码格式返回请求的参数集合 ziqiu.zhang 2009.1.19
/// </summary>
/// <param name="request">当前请求的request对象</param>
/// <param name="encode">编码格式字符串</param>
/// <returns>键为参数名,值为参数值的NameValue集合</returns>
public static NameValueCollection GetRequestParameters(HttpRequest request, string encode)
{
NameValueCollection result = null;
Encoding destEncode = null;

//获取指定编码格式的Encoding对象
if (!String.IsNullOrEmpty(encode))
{
try
{
//获取指定的编码格式
destEncode = Encoding.GetEncoding(encode);
}
catch
{
//如果获取指定编码格式失败,则设置为null
destEncode = null;
}
}

//根据不同的HttpMethod方式,获取请求的参数.如果没有Encoding对象则使用服务器端默认的编码.
if (request.HttpMethod == "POST")
{
if (null != destEncode)
{
Stream resStream = request.InputStream;
byte[] filecontent = new byte[resStream.Length];
resStream.Read(filecontent, 0, filecontent.Length);
string postquery = destEncode.GetString(filecontent);
result = HttpUtility.ParseQueryString(postquery, destEncode);
}
else
{
result = request.Form;
}
}
else
{
if (null != destEncode)
{
result = System.Web.HttpUtility.ParseQueryString(request.Url.Query, destEncode);
}
else
{
result = request.QueryString;
}
}

//返回结果
return result;
}

通过上面的方法, 无论是Get请求还是Post请求, 我们都可以使用自己指定的编码格式获取参数.如果有人认为写这个方法是在自找麻烦,请看"二.错误观点"中的第三条.

此方法返回的是一个NameValueCollection对象,判断是否有某个参数时不能使用检查是否存在key值的方法.而是要通key获取值,然后判断值是否为null(和List有些不同): 


//获取参数, 假设paramList是一个NameValueCollection对象
p1= paramList["p1"];

//判断是否存在此参数,如果不存在则p1为null
if ( !( String.IsNullOrEmpty(p1) )
{...}

另外本方法如果没有传递Encoding或者传递的字符串无法转换成强类型的Encoding对象, 则使用服务器端默认编码格式(即直接使用Request对象的QueryString和Form获取参数).

六.Javascript编码方法

发送请求的一方叫做客户端.我们经常需要使用Javascript在客户端编码中文参数.下面javascript中和编码有关的函数:


函数名称


函数说明


解释


escape()


escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。


该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。其他所有的字符都会被转义序列替换。

 

[已过时] 请使用 encodeURI() 或 encodeURIComponent()


unescape()


unescape() 函数可对通过 escape() 编码的字符串进行解码。


该函数的工作原理是这样的:通过找到形式为 %xx 和 %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx 和 \uxxxx 替换这样的字符序列进行解码。

 

[已过时] 请使用 decodeURI() 或 decodeURIComponent()


encodeURI()


encodeURI() 函数可把字符串作为 URI 进行编码。

 


该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。

该方法的目的是对 URI 进行完整的编码,因此对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的:;/?:@&=+$,#

 

[提示] 如果 URI 的参数中含有不能转移的字符,则应当使用 encodeURIComponent() 方法分别对各参数进行编码。


decodeURI()


decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。

 


 


encodeURIComponent()


encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。

 


该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。

其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。

 

[提示] 此方法会编码URI中的特殊字符


decodeURIComponent()


decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。


 

escape和unescape在V3版本的标准中已经不在推荐使用.应该用encodeURI和encodeURIComponent方法.对于一个URI(URL也是一中URI),如果我们希望将它作为完整的网址发送请求, 但是上面带有中文, 则应该使用encodeURI方法.如果是要编码参数,则应该使用encodeURIComponent.

下面举例说明这两个方法的区别:

document.write(encodeURIComponent("http://www.w3school.com.cn")+ "<br />")

document.write(encodeURI("http://www.w3school.com.cn")+ "<br />")

结果

http%3A%2F%2Fwww.w3school.com.cn

http://www.w3school.com.cn

七.浏览器自动编码

Get请求

对于Get方式发送的请求, 不同的浏览器使用不同的编码方式自动为中文参数编码.

比如:Firefox/3.0.5 使用UTF-8, IE6使用GB2312.

Post请求

对于Post方式发送的请求, 表单中的参数值对是通过request body发送给服务器,此时浏览器会根据网页的ContentType("text/html; charset=GBK")中指定的编码进行对表单中的数据进行编码,然后发给服务器。在HTML代码的Head中添加:

<meta http-equiv="Content-Type" content="text/html;charset=gb2312" />

Firefox/3.0.5 会使用根据charset中设置的编码格式编码post的中文参数.

IE6不起作用.

实验表明使用客户端浏览器默认编码格式具有不确定性.所以传递中文时我们要手工编码参数.

八.总结

写这篇文章的目的是提醒Web程序员要注意浏览器的自动编码, 在一个项目中按照本文提供的解决方案将避免中文参数传递带来的乱码问题.在看了YJingLee's Blog的"CnBlogs博文排版技巧"后我对本文重新进行了整理.

时间: 2024-10-22 16:29:50

一起谈.NET技术,参数编码 完全解决方案的相关文章

参数编码 完全解决方案

参数编码规范一.摘要 我们经常要在页面传递中文数据,但是往往被文字编码所困惑.有时不了解到底是浏览器编码问题还是服务器编码问题.本文分析了互联网传递数据的编码原理, 并且提出了完善易用的解决方案. 二.原则 避免在get或者post参数时直接传递中文字符.中文参数需要经过编码后再传递.服务器端要使用相同的编码格式进行解码 三.错误观点 1.很多程序员认为url中可以传递中文.  url中并不能携带中文参数.如果我们在浏览器中输入"http://localhost/?a=中文",感觉上我

一起谈.NET技术,微软 Share Point 2010 企业应用解决方案

SharePoint 2010功能及改进 SharePoint 2010分为两个版本SharePoint Foundation 2010和SharePoint Server 2010,其中SharePoint Foundation 2010是WSS 3.0的升级,而SharePoint Server 2010则是MOSS 2007的升级(文中如无特别说明则SharePoint 2010是二者统称).SharePoint 2010有网站.社区.内容.搜索.见解和整合应用等6大功能模块,与MOSS

想知道手机技术参数

问题描述 如何或在什么地方一,查找手机的技术参数--1.手机的CPU速度,缓存大小,2.是否支持Jsr75及MIDP2.0等3.如何知道堆内存大小.栈内存大小?4.如何知道Jarsize,heapsize?5.出产日期等二,调入阅读的文档大小与手机缓存大小有关吗?如缓存只有20k,是否调入的文档加程序的大小要小于20k.三,请不要回该贴,请回chran1118888@163.com01086918436 解决方案 解决方案二:引用楼主chr1118888的帖子: 如何或在什么地方一,查找手机的技

流媒体音视频各种技术参数概念及详解教程

分辨率概念 分辨率是和图像相关的一个重要概念,它是衡量图像细节表现力的技术参数.分辨率高是保证彩色显示器清晰度的重要前提.分辨率是体现屏幕图像的精密度,是指显示器所能显示的点数的多少.通常,"分辨率"被表示成每一个方向上的像素数量,分辨率越高,可显示的点数越多,画面就越精细. 视频分辨率是指视频成像产品所成图像的大小或尺寸.目前手机台常见的视像分辨率有480x270, 640×360,1024×768.屏幕长宽比是16:9和5:4. 码率概念 码率(Data Rate),码率就是数据传

使用大数据技术和Hadoop的解决方案

但是,您如何确定哪些数据是重要数据,如何确定该信息有多大比例是有效的.值得包含在报告中或有助于检测警报条件?本文将介绍为 大量机器数据集的使用提供支持的一些挑战,以及使用http://www.aliyun.com/zixun/aggregation/13568.html">大数据技术和 Hadoop 的解决方案.在探索数据存储和供给的基本机制之前,需要考虑您要存储何种信息,如何存储它,以及打算存储多长时间. Hadoop 的一个较大.但并不总是被提出来的问题是,它提供了一个只能附加的数据存

交换机的重要技术参数

下面我将对交换机的重要技术参数作一一介绍,方便网友在选购交换机时比较不同厂商的不同产品.每一个参数都影响到交换机的性能.功能和不同集成特性. 1.转发技术:交换机采用直通转发技术或存储转发技术? 2.延时:交换机数据交换延时多少? 3.管理功能:交换机提供给拥护多少可管理功能? 4.单/多MAC地址类型:每个端口是单MAC地址,还是多MAC地址? 5.外接监视支持:交换机是否允许外接监视工具管理端口.电路或交换机所有流量? 6.扩展树:交换机是否提供扩展树算法或其他算法,检测并限制拓扑环? 7.

《创业家》牛文文:少谈点模式多谈点技术

"模式"如同当年的"主义",流行于各种创业大赛.创业励志节目.论坛的"街头"式秀场 文/创业家 牛文文 "美国某某公司你知道吧?就是刚被戴尔.惠普.思科十几亿美元抢购的那家.我们的模式和它的一样,现在还没赢利,可将来起码有十几亿人民币的市值." "我开了小煤矿,但煤运不出去,上商学院之后受到启发,想搞模式创新,具体讲就是想在铁路边上搞个煤炭物流开发区,建一个大的物流和信息流平台,把分散的煤炭集中在我这个园区,这样和铁

一起谈.NET技术,VS2010 测试功能之旅:编码的UI测试(4)-通过编写测试代码的方式建立UI测试(下)

回顾 最近比较忙,距离上次更新的时间较久,见谅. 在本章上部分,介绍了"添加用户"窗口的测试代码编写.想必大家也看到了,在UIMap.cs文件中实现自定义编码是一件很轻松的事情,接下来将介绍下个部分,查询用户窗体的测试代码的编写,以及他们测试的关联. 示例程序介绍 系统主窗口:(下载点我) 该系统拥有两个功能,"添加用户"和"查询用户": 点击添加用户后,进入添加用户子窗体:("添加用户"窗口的测试代码编写在上部分已经实现)

一起谈.NET技术,使用编码招式(Coding Katas)、BDD和VS2010项目模板

通过编码招式和行为驱动开发,我受到了一些启迪,感觉良好.然而,当我意识到如果以后我就用这种方式编写单元测试.进行开发工作,那会相当痛苦,因为每次都要引入Eric Lee的ContextSpecification.如果我可以简单地选定一个BDD的单元测试项目,然后项目创建后我就拥有了所有项目所需的文件,那就容易多了.稍作查询之后,我找到了一些项目模板导出向导(Project Template Export Wizard)的参考资料,似乎这就是最适合我的解决方案. 为了能试试这个例子,你要从Visu