問題描述
404(找不到請求資源)錯誤是一種最常見的web服務器報錯,最近在啟用URL Rewrite模塊的服務器上遇到一個比較特殊的404錯誤,所請求的資源在正確的位置,但是從客戶端請求始終報錯404。
出錯環境中服務器分為前端服務器和后端服務器,均為Windows Server 2008 R2 (IIS 7.5),前端服務器通過URL Rewrite模塊將請求改寫為真正的后端服務器請求,請求后端服務器資源並回復給客戶端。
客戶端請求以下文件時報404錯誤。
http://localhost/abc.svc
URL Rewrite的目標路徑是http://backgroundserver/abc.svc,在前段服務器上直接請求該鏈接沒有問題。
問題調試
我們通過IIS內置錯誤追蹤機制failed request tracing來查看該錯誤。在該網站的web.config中<configuration>\<system.webServer>節點下添加如下配置,這個配置節點的意思是追蹤服務器所有返回為404的請求,記錄所有模塊處理過程的詳細信息。
<tracing> <traceFailedRequests> <add path="*"> <traceAreas> <add provider="ASP" verbosity="Verbose" /> <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" /> <add provider="ISAPI Extension" verbosity="Verbose" /> <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI,Rewrite,RequestRouting" verbosity="Verbose" /> </traceAreas> <failureDefinitions timeTaken="00:00:00" statusCodes="404" /> </add> </traceFailedRequests> </tracing> </system.webServer> </configuration>
也可以通過IIS Manager界面來添加這個配置。具體可以參考http://www.iis.net/learn/troubleshoot/using-failed-request-tracing/troubleshooting-failed-requests-using-tracing-in-iis
配置了failed request tracing之后,再次請求該鏈接並得到404報錯,之后到failed request tracing默認路徑下找到生成的日志文件,通過IE打開。
C:\inetpub\logs\FailedReqLogFiles\W3SVC1\
在該日志summary中有兩個關鍵信息值得注意,
- 出錯模塊為ServiceModel-4.0
- 出錯階段為AUTHENTICATE_REQUEST
以下是一個正常的404報錯,可以看到正常情況下
- 出錯模塊為IIS Web Core
- 出錯階段為MapRequestHandler
接下來我們了解一下URL Rewrite的工作原理。參考下圖,
URL Rewrite模塊在Begin Request階段就會將請求按照配置的規則改寫。之后交給后續模塊繼續處理。Authenticate Request階段負責對請求進行認證。之后會到Map Handler階段,這時Application Request Routing模塊會檢查該請求是否需要forward給其他服務器,如果需要則向其他服務器發送請求,並將相應結果交給后續模塊,最終回傳給客戶端。
我們的這個404報錯居然處在了Authenticate Request階段,說明Application Request Routing模塊還沒有來的及請求后台服務器就報了404錯誤。
通過failed request tracing日志的詳細日志也可以看到相應的出錯過程。
解決方案
現在問題發生的原因明確的了,是ServiceModel-4.0模塊在Authenticate_Request階段截獲了請求並驗證該資源是否存在於本地服務器,由於資源在后台服務器,需要借助URL Rewrite和Application Request Routing模塊,因此報了404錯誤。
要解決該問題,我們到IIS Manager里面找到處理該模塊的Handler Mapping。由於我們在前段服務器網站只需要用URL Rewrite將請求改到后端服務器,不需要該模塊來處理svc文件請求,因此我們可以直接將其刪除。
再次請求之前出錯的鏈接,得到了正確的頁面,404問題解決了。
希望以上內容對你有所幫助。