IIS6 404自定义错误页面带来乱码的处理方法

bug logo  ASP.NET MVC在上绝少出现因为文件编码问题而导致的乱码问题,即使出现,也可以通过web.config的配置或者修改文件编码来解决,然而今天碰到的这例,却无法使用这些方法来解决,无论怎么修改,乱码依旧。让人懊恼不已!

  问题是这样的:ASP.NET MVC2在IIS6上进行部署,由于系统还有一些暂时未能完全使用MVC架构的代码存在,就利用了IIS6中的URL重定向机制,将404错误页面转发回系统页面进行处理,在系统中进行判定页面是否不存在或者重新配置页面地址重定向,让MVC Routing能够进行处理。想法是不错的,处理英文的时候也是非常顺畅的,但碰到中文的时候,系统就情不自禁的抽起疯来,根本就无法达到预期的效果。—— 一查,参数未解码的时候中文编码都是%ufffd,一解码全是乱码,能达到预期效果反而奇怪了!

  开始以为是配置上问题,检查了下config文件,发现request和response的Encoding都是UTF8,进而检查文件编码,也是UTF8,这和配置中的编码一致。理论上这样乱码应该不存在的,但理论往往和实际相差甚远!只好进一步检查,在历尽千辛万苦,最后发现问题原来出现在IIS的URL重定向上。当访问一个不存在的页面(含中文参数),IIS6会触发404错误,并将产生错误的内容重定向到指定的URL上,目标页面获取参数信息,但在处理中文时,需要进行解码,但根据IIS6定向过来的内容解码就会出现乱码,这就导致组合后的新地址经过MVC 路由后,无法正确的加载指定功能 —— 参数不对。

  以前我一直的说法是找到问题就是成功解决问题的关键,这话的确没错,接下来要解决它,只需要找到为什么IIS6传递过来的内容会出现解码错误即可。然而,随着进一步的检查发现,问题远没有想象的那么简单,IIS6.0在处理字串的时候默认使用的是(注:这里比较乱,有说GBK,也有说GB2312,还有说是ASCII,谁知道请告诉我,IIS6使用的默认编码是什么?这里用Unicode)。这个编码和我们有什么关系么?—— 我现在是没有想出具体的关系的,但是肯定是有关系的。以下为本人观点,猜测成分比较大,如果你有更详细的这方面资料请分享,将非常感激。

  在我们站点都使用UTF8的时候—— 这里我们需要补充个基础知识,UTF8的字符集是明显大于Unicode编码的。当IIS6检测到错误的时候,需要将UTF8转为IIS6的编码,并进行封装再转交给我们站点内处理,由于IIS6使用的是Unicode编码,在将UTF8字串转为Unicode时,因为字符集不够,所以出现无法转换现象,在无法转换是,系统用%ufffd来表示未能转换的字符。因此使用Unicode处理数据,再转交给站点内模块,程序设置为UTF8编码,UTF8去解码Unicode编码字串,结果可想而知,解码出来的中文自然而然就是乱码。这个思路大概用下面的图来概括(注:图中用的是GBK表示)

iis6.0 自定义错误页面的处理流程示意图

这个图片描述的可能有误,但迄今为止尝试了很多各种编码的组合方式,都没有很好的将中文转成在程序中获取到的那种样子,所以也不能确定到底IIS6使用的是什么东西。

  解决方法网上有提供一些,但他们能真正的解决问题吗?

  1. 最多人的建议是使用UrlEncode方法将所有的中文进行编码之后传到服务端。

  但这种方法对于自定义错误页面的方法根本就无法解决。IIS6同样会将URL中的中文变成乱码。

  2. 另一种比较多的方法是在BeginRequest事件中处理,用Encoding去尝试转码来解决编码问题。

  个人认为这个方法也没能真正解决问题,因为我们一旦获取到的是%ufffd这种的参数时,就意味着我们的参数已经出现问题了。再说,这个方法和前一种方法一样,真正错误的是在IIS6中的自定错误页面过来的参数,在这之前已经出现错误,后面怎么弥补都无济于事。

  调试可以发现,在Request对象中,虽然QueryString,Url中的所有的都是乱码,但是RawUrl是正常的。如下图:

iis6自定义错误页面跳转过来时出现乱码

  经过多次的测试发现,如果要比较好的解决这个问题,可以使用以下两种方法:

  1. 如果真的要在BeginRequest中处理乱码——当然,你也可以在你需要获取参数的时候进行处理,使用RawUrl。因为只有这个参数能够完整的保留中文信息。

  2. 对当前处理逻辑调整,直接处理掉可以处理的页面内容,而不要依赖IIS6的自定义错误页面来解决在程序中原本是非错误的页面,比如:数据库中页面,先要进行404跳转之后,再进入指定页面再来处理,这种处理方式比较闹心,但当下却还是有一些在用,我这篇文章就是这么来的。 

  当然了,上面的建议都是理想状态的,对于现存的项目来说,要实现不是一时半会,还需要仔细斟酌。针对我当前特定版本的解决方法,项目是MVC的,直接在Route中添加了对应规则,让这些都转入指定的模块中"销毁"吧,这和上述第二点原理一样,但却治不了根。 

  根据网上的一些信息综合起来看,这个问题应该是出自IIS6内部,不仅是中文,就连很多国际友人在做开发的时候也碰到过各种各样的Unicode Problem。有些反馈是说在IIS7下面没有这种现象,这个我没有测试,如果哪位有条件的可以测试下。

 

  问题暂时解决了,可以先休息会,毕竟这个问题折腾了我好几天啊!

 

参考:

CSDN 设置404页面所导致的乱码问题的帖子: http://bbs.csdn.net/topics/390358009

IIS.NET上面关于Unicode字符丢失的帖子:http://forums.iis.net/t/1085091.aspx/1

 

Saturday, June 01, 2013 | .NET技术 其他技术

文章评论

No comments posted yet.

发表评论

Please add 5 and 7 and type the answer here:

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。