今天在处理Google网站管理员中的500错误时发现这样一些URL:

http://www.cnblogs.com/Garnai/tag/3D%3F%96%CA/
http://www.cnblogs.com/henryfan/tag/%3F%3F%3F%90%B6%90%AC%3F%8C%8F/
http://www.cnblogs.com/zhangpengshou/tag/%3F%96%DA%3F%97%9D%94V%8FC%3F/
http://www.cnblogs.com/henryfan/tag/%3F%3F%3F%90%B6%90%AC%3F%8C%8F/
...

这些URL不仅出现500错误,而且不显示自定义错误,只显示ASP.NET的默认错误页面:

服务器日志中记录具体的错误信息是:

[ArgumentOutOfRangeException: 在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符。 (异常来自 HRESULT:0x80070459)]
System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) +0
System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode) +13563503
System.Web.Hosting.IIS7WorkerRequest.GetServerVariableInternal(String name) +50
System.Web.Hosting.IIS7WorkerRequest.ReadRequestHeaders() +144
System.Web.Hosting.IIS7WorkerRequest.GetKnownRequestHeader(Int32 index) +109
System.Web.HttpWorkerRequest.HasEntityBody() +27
System.Web.HttpRequest.GetEncodingFromHeaders() +126
System.Web.HttpRequest.get_ContentEncoding() +162
System.Web.HttpRequest.get_QueryStringEncoding() +10
System.Web.HttpRequest.get_QueryStringText() +209
System.Web.HttpRequest.ValidateInputIfRequiredByConfig() +87
System.Web.PipelineStepManager.ValidateHelper(HttpContext context) +55

对应的英文错误信息是:

No mapping for the Unicode character exists in the target multi-byte code page.

从这些出错的URL中观察到了一个规律:都包含%3F这个编码,解码出来对应的字符是?。

从错误信息的代码执行堆栈信息 System.Web.HttpRequest.get_QueryStringText() 中,可以看出错误发生在从URL中读取查询字符串的时候。

可是出错的URL中并没有查询字符串。。。

后来突然想到,ASP.NET是先进行UrlDecode,然后再进行get_QueryStringText()的。

比如将  http://www.cnblogs.com/Garnai/tag/3D%3F%96%CA/ 进行URLDecode之后得到的URL是:

http://www.cnblogs.com/Garnai/tag/3D?柺/

看到没有,出现了问号,变成有查询字符串的URL。于是,ASP.NET将问号之后的字符作为key进行读取,由于key是不支持中文的,于是引发“在多字节的目标代码页中,没有此Unicode字符可以映射到的字符”。如果ASP.NET先进行get_QueryStringText(),再进行UrlDecode就不会触发这个问题,可是ASP.NET偏偏不这么干。

那如何解决这个问题?

虽然问题出在ASP.NET,但我们无法改变ASP.NET,只能另辟蹊径。

既然是ASP.NET处理上的问题,那我们别无选择,只能抢在ASP.NET之前拦截这样的URL请求,而进行这样的拦截最简单的工具就是IIS的Url Rewrite module。

根据我们的应用场景,在rewriteRules.config中添加一条规则——在URL中如果/tag/之后出现问号就直接返回404,规则定义如下:

<rule name="block_invalid_tag_url" stopProcessing="true">
<match url="^[^/]+/tag/.*?\?.*$" />
<action type="CustomResponse" statusCode="404" statusReason="The request URL is invalid"
statusDescription="The request URL is invalid" />
</rule>

然后就搞定了这个问题,写了这篇博客。

解决“在多字节的目标代码页中,没有此Unicode字符可以映射到的字符”的更多相关文章

  1. 在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符。 (#1113)

    报错 在使用MySQL-Front导入sql文件时报错1113:在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符. (#1113) 解决方案 导入.sql文件时,单击 选择文件对话 ...

  2. mysql-front导入数据失败:“在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符”

    mysql-front导入sql文件失败,弹出框显示如下: 解决方法:在选择文件时,选择合适的字符集即可 参考:http://www.th7.cn/db/mysql/201604/185149.sht ...

  3. excel导入sql server 文本被截断,或者一个或多个字符在目标代码页中没有匹配项 错误处理

    excel导入sql server 文本被截断,或者一个或多个字符在目标代码页中没有匹配项 错误处理方法: 方案1:修改注册表 出现文本被截断的原因是SQL Server的导入导出为了确定数据表的字段 ...

  4. Excel 导入 Sql Server出错——“文本被截断,或者一个或多个字符在目标代码页中没有匹配项”错误的解决

    有人说应该先转成Access, 再转到Sql Server. 其实用处并不大, 要截断的还是被截断了. 原因是,SQL Server的导入导出为了确定数据表的字段类型,取excel文件的前8行来判别. ...

  5. Excel导入数据到Sql server 中出错:“文本被截断,或者一个或多个字符在目标代码页中没有匹配项”

    从Excel导入数据到Sql server 时,由于表中的数据有的很长,导入时出现如下错误(如果数据不是很长,255内以内,则不会出现错误): 出错原因: SQL Server的导入导出为了确定数据表 ...

  6. sqlserver导入Excel数据 总是报错:错误 0xc020901c: 数据流任务 1: 输出“Excel 源输出”(55) 上的 输出列“T2”(64) 出错。返回的列状态是:“文本被截断,或者一个或多个字符在目标代码页中没有匹配项

    在网络上搜索解决办法,解决办法是把excel导入到access数据库中,再把access数据库导入到sqlsever中,公司机器上不让安装office工具,问了一个同事得到的回答是把数据中很长的那行数 ...

  7. 同构体字符串(如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。)

    示例 1: 输入: s = "egg", t = "add" 输出: true 示例 2: 输入: s = "foo", t = " ...

  8. Windows代码页、区域

    目录 第1章代码页    1 1 代码页    1 1.1 单字节字符集    1 1.2 双字节字符集    1 1.3 多字节字符集    1 1.4 ANSI代码页    2 2 枚举代码页   ...

  9. 刨根究底字符编码之七——ANSI编码与代码页(Code Page)

    ANSI编码与代码页(Code Page) 一.ANSI编码 1. 如前所述,在全世界所有国家和民族的文字符号统一编码的Unicode编码方案问世之前,各个国家.民族为了用计算机记录并显示自己的字符, ...

随机推荐

  1. error C2259: 'CException' : cannot instantiate abstract class

    vc6.0编译通过,VS2008则报错 解决方法: 把CException改为CUserException

  2. [笔记]Modelsim系列01:编译Altera库的方法

    意义:一劳永逸,不用每次对那些包含Quartus II生成文件的工程进行功能仿真时,都需要重新编译一堆东西.节约时间成本. 版本:ModelSim SE 6.5d 打开Modelsim软件,默认会打开 ...

  3. C++之jsoncpp学习

    最新由于客户端要用到jsoncpp,所以自己也跟着项目的需求学了一下jsoncpp.以前没用过xml,但是感觉接触json后,还蛮好用的. 参考地址 http://jsoncpp.sourceforg ...

  4. 使用阿里Docker镜像加速器加速

    在阿里开发者平台注册开发者账号 https://dev.aliyun.com/search.html 注册之后可以访问Docker镜像服务 https://cr.console.aliyun.com/ ...

  5. 使用Innosetup制作安装包的一些技巧

    1. 选择安装界面上的图片 [Setup] ;设置界面上的两个图片 WizardImageFile=WizModernImage.bmp WizardSmallImageFile=WizSmallIm ...

  6. UI组件之Group

    当Group旋转或缩放时,它的孩子们正常绘制,并且Batch变换后正确的旋转或缩放. 绘制Group前,Batch flush使得变换可以设置.有很多Group时这将可能成为性能瓶颈.如果在一组演员不 ...

  7. 【Android UI设计与开发】第05期:引导界面(五)实现应用程序只启动一次引导界面

    [Android UI设计与开发]第05期:引导界面(五)实现应用程序只启动一次引导界面 jingqing 发表于 2013-7-11 14:42:02 浏览(229501) 这篇文章算是对整个引导界 ...

  8. PHP魔法方法的使用

    1.__get / __set 当类没有要存取的属性时,就调用这两个函数 $obj = new IMooc\Object();$obj->title = "hello";ec ...

  9. AIX主机信任关系配置

    1.配置主机信任关系的时候,需要先在两台主机/etc/hosts文件中添加要信任主机的IP,假设有(192.168.8.190 aix190,192.168.8.191 aix191)2个主机,在19 ...

  10. CentOS7安装mysql5.7.11

    开始安装 yum update yum install wget wget http://repo.mysql.com/mysql57-community-release-el7-7.noarch.r ...