开发者社区> 技术小美> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

参数编码 完全解决方案 (转)

简介:
+关注继续查看
< DOCTYPE html PUBLIC -WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml-strictdtd>
参数编码规范一.摘要

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

二.原则

避免在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博文排版技巧"后我对本文重新进行了整理.
出处:http://www.cnblogs.com/zhangziqiu/


本文转自 netcorner 博客园博客,原文链接: http://www.cnblogs.com/netcorner/archive/2010/03/02/2912029.html  ,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
【集合框架】JDK1.8源码分析之IdentityHashMap(四)
  前面已经分析了HashMap与LinkedHashMap,现在我们来分析不太常用的IdentityHashMap,从它的名字上也可以看出来用于表示唯一的HashMap,仔细分析了其源码,发现其数据结构与HashMap使用的数据结构完全不同,因为在继承关系上面,他们两没有任何关系。下面,进入我们的分析阶段。
22 0
【集合框架】JDK1.8源码分析之IdentityHashMap(四)
  前面已经分析了HashMap与LinkedHashMap,现在我们来分析不太常用的IdentityHashMap,从它的名字上也可以看出来用于表示唯一的HashMap,仔细分析了其源码,发现其数据结构与HashMap使用的数据结构完全不同,因为在继承关系上面,他们两没有任何关系。下面,进入我们的分析阶段。
25 0
常见的编码错误,再不避免就完了!
犯错乃人之常情。然而,开发人员所犯的许多错误是可以避免的。如果能避免本文提到的这些常见错误,就能写出更好、更简洁的代码。
533 0
租用云服务器之前 这些坑你得擦亮眼睛
租用云服务器 前面这些坑你得擦亮眼睛 企业上云或者个人建站,都得需要一个服务器空间来放置网站程序、应用等,所以服务器租用是现在广大企业和站长不可忽视的环节。由于云服务器快速普及,性价比也在快速提升,越来越多的用户都开始选择使用云服务器了。
812 0
编码
很多人都把Unicode编码挂在嘴边,其实咱们现实生活中遇到的编码基本都是Unicode的 因为Unicode兼容了大多数老版本的编码规范例如 ASCII Unicode编码定义了这个世界上几乎所有字符(就是你眼睛看到的长那个样子的符号)的数字表示 也就是说Unicode为每个字符发了一张身份证,这张身份证上有一串唯一的数字ID确定了这个字符 在这个纷乱世界上存在的唯一性。
1047 0
编码
   在计算机的世界里,所有的文字,数值都只是一连串的0和1。这些0和1对于设计者来说实在是难以理解;于是就产生了各种方式的编码;它们指定一个数值来代表某个字符; 比如常用的字符编码系统ASCII   虽然各类的编码系统合起来有数百种之多,却没有一种是包含足够的字符、标点符号及常用的专业技术符号...
675 0
+关注
6819
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载