解決“在多字節的目標代碼頁中,沒有此Unicode字符可以映射到的字符”


今天在處理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>

然后就搞定了這個問題,寫了這篇博客。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM