針對在 Visual Studio 中執行但在生產 IIS 伺服器上失敗的 Web API2 應用程式進行疑難排解
本文件說明如何針對部署到生產 IIS 伺服器的 Web API2 應用程式進行疑難排解。 它會解決常見的 HTTP 405 和 501 錯誤。
本教學課程中使用的軟體
- Internet Information Services (IIS) (版本 7 或更新版本)
- Web API
Web API 應用程式通常會使用數個 HTTP 動詞:GET、POST、PUT、DELETE,有時則是 PATCH。 也就是說,開發人員可能會遇到這些動詞是由另一個 IIS 模組在其生產 IIS 伺服器上實作的情況,這會導致 Web API 控制器在 Visual Studio 或開發伺服器上正常運作的情況,會在部署至生產 IIS 伺服器時傳回 HTTP 405 錯誤。
造成 HTTP 405 錯誤的原因
瞭解如何針對 HTTP 405 錯誤進行疑難排解的第一個步驟,是瞭解 HTTP 405 錯誤的實際意義。 HTTP 的主要管理文件是 RFC 2616,它將 HTTP 405 狀態代碼定義為 [不允許的方法],並進一步將此狀態代碼描述為「對於由 Request-URI 識別的資源,不允許使用 Request-Line 中指定的方法」的情況。換句話說,HTTP 動詞不允許用於 HTTP 用戶端要求的特定 URL。
簡短檢閱時,以下是 RFC 2616、RFC 4918 和 RFC 5789 中定義的數個最常使用的 HTTP 方法:
HTTP 方法 | 描述 |
---|---|
取得 | 這個方法可用來從 URI 擷取資料,而且可能是最常用的 HTTP 方法。 |
HEAD | 這個方法與 GET 方法非常類似,不同之處在於它實際上不會從要求 URI 擷取資料 - 它只會擷取 HTTP 狀態。 |
POST | 這個方法通常用來將新資料傳送至 URI;POST 通常用來提交表單資料。 |
PUT | 這個方法通常用來將原始資料傳送至 URI;PUT 通常用來將 JSON 或 XML 資料提交至 Web API 應用程式。 |
DELETE | 這個方法可用來從 URI 移除資料。 |
OPTIONS | 這個方法通常用來擷取 URI 支援的 HTTP 方法清單。 |
COPY MOVE | 這兩種方法會與 WebDAV 搭配使用,其用途是自我說明。 |
MKCOL | 這個方法會與 WebDAV 搭配使用,並用來在指定的 URI 建立集合 (例如目錄)。 |
PROPFIND PROPPATCH | 這兩種方法會與 WebDAV 搭配使用,用來查詢或設定 URI 的屬性。 |
LOCK UNLOCK | 這兩種方法會與 WebDAV 搭配使用,用來鎖定/解除鎖定撰寫時要求 URI 所識別的資源。 |
PATCH | 這個方法可用來修改現有的 HTTP 資源。 |
當其中一個 HTTP 方法設定為在伺服器上使用時,伺服器會回應 HTTP 狀態和其他適用於要求的資料。 (例如,GET 方法可能會收到 HTTP 200 確定回應,而 PUT 方法可能會收到 HTTP 201 已建立的回應。
如果未將 HTTP 方法設定為在伺服器上使用,伺服器將會以 HTTP 501 未實作 的錯誤回應。
不過,當 HTTP 方法設定為在伺服器上使用,但已針對指定的 URI 停用時,伺服器會以 HTTP 405 方法不允許 的錯誤回應。
範例 HTTP 405 錯誤
下列範例 HTTP 要求和回應說明 HTTP 用戶端嘗試將值放到 Web 伺服器上的 Web API 應用程式的情況,而伺服器會傳回 HTTP 錯誤,指出不允許 PUT 方法:
HTTP 要求:
PUT /api/values/1 HTTP/1.1
Content-type: application/json
Host: localhost
Accept: */*
Content-Length: 12
"Some Value"
HTTP 回應:
HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Date: Wed, 15 May 2013 02:38:57 GMT
Content-Length: 72
{"Message":"The requested resource does not support http method 'PUT'."}
在此範例中,HTTP 用戶端會將有效的 JSON 要求傳送至網頁伺服器上的 Web API 應用程式的 URL,但伺服器傳回 HTTP 405 錯誤訊息,表示 URL 不允許 PUT 方法。 相反地,如果要求 URI 不符合 Web API 應用程式的路由,伺服器會傳回 HTTP 404 找不到錯誤。
解決 HTTP 405 錯誤
有數個原因導致不允許特定 HTTP 動詞,但 IIS 中有一個主要案例是此錯誤的前置原因:針對相同的動詞/方法定義多個處理常式,而其中一個處理常式會封鎖預期的處理常式處理要求。 作為說明,IIS 根據 applicationHost.config 和 web.config 檔案中的順序處理常式項目,從頭到尾處理處理常式,其中路徑、動詞、資源等的第一個相符組合將用於處理要求。
下列範例是 IIS 伺服器的 applicationHost.config 檔案摘錄,在使用 PUT 方法將資料提交至 Web API 應用程式時,傳回 HTTP 405 錯誤。 在此摘錄中,會定義數個 HTTP 處理常式,而且每個處理常式都有一組不同的 HTTP 方法,其已設定 - 清單中的最後一個項目是靜態內容處理常式,這是在其他處理常式有機會檢查要求之後使用的預設處理常式:
<handlers accessPolicy="Read, Script">
<add name="WebDAV"
path="*"
verb="PROPFIND,PROPPATCH,MKCOL,PUT,COPY,DELETE,MOVE,LOCK,UNLOCK"
modules="WebDAVModule"
resourceType="Unspecified"
requireAccess="None" />
<add name="ISAPI-dll"
path="*.dll"
verb="*"
modules="IsapiModule"
resourceType="File"
requireAccess="Execute"
allowPathInfo="true" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
<!-- Additional handlers will be defined here. -->
<add name="StaticFile"
path="*"
verb="*"
modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule"
resourceType="Either"
requireAccess="Read" />
</handlers>
在上述範例中,webDAV 處理常式和適用於 ASP.NET 的擴充功能 URL 處理常式 (用於 Web API) 已明確定義為個別的 HTTP 方法清單。 請注意,ISAPI DLL 處理常式已針對所有 HTTP 方法設定,雖然此設定不一定會造成錯誤。 不過,針對 HTTP 405 錯誤進行疑難排解時,需要考慮這類組態設定。
在上述範例中,ISAPI DLL 處理常式不是問題;事實上,問題並未定義於 IIS 伺服器的 applicationHost.config 檔案中,問題是由在 Visual Studio 中建立 Web API 應用程式時在 web.config 檔案中建立的專案所造成。 下列來自應用程式的 web.config 檔案摘錄顯示問題的位置:
<handlers accessPolicy="Read, Script">
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
</handlers>
在此摘錄中,會重新定義適用於 ASP.NET 的無擴充功能 URL 處理常式,以包含將搭配 Web API 應用程式使用的其他 HTTP 方法。 不過,因為 WebDAV 處理常式定義了一組類似的 HTTP 方法,因此會發生衝突。 在此特定案例中,即使包含 Web API 應用程式的網站已停用 WebDAV,WEBDAV 處理常式還是由 IIS 定義和載入。 在處理 HTTP PUT 要求期間,IIS 會呼叫 WebDAV 模組,因為它已針對 PUT 動詞定義。 呼叫 WebDAV 模組時,它會檢查其設定並查看其是否已停用,因此它會針對類似 WebDAV 要求的任何要求傳回 HTTP 405 方法不允許錯誤。 若要解決此問題,您應該從定義 Web API 應用程式的網站 HTTP 模組清單中移除 WebDAV。 以下範例顯示了它可能的樣子:
<handlers accessPolicy="Read, Script">
<remove name="WebDAV" />
<remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
<add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"
path="*."
verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS"
modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll"
preCondition="classicMode,runtimeVersionv4.0,bitness64"
responseBufferLimit="0" />
</handlers>
此案例通常會在應用程式從開發環境發佈至 IIS 生產環境之後發生,因為處理常式/模組清單在開發與生產環境之間不同而發生。 例如,如果您使用 Visual Studio 2012 或更新版本來開發 Web API 應用程式,IIS Express 是測試的預設 Web 伺服器。 此開發網頁伺服器是伺服器產品中隨附的完整 IIS 功能相應減少版本,此開發網頁伺服器包含一些針對開發案例所新增的變更。 例如,WebDAV 模組通常安裝在執行完整 IIS 版本的生產 Web 伺服器上,但可能未使用。 IIS (IIS Express) 的開發版本會安裝 WebDAV 模組,但 WebDAV 模組的項目會刻意標記為註解,因此除非您特別改變 IIS Express 組態設定,將 WebDAV 功能新增至 IIS Express 安裝,否則 WebDAV 模組永遠不會載入 IIS Express。 因此,您的 Web 應用程式可能會在開發電腦上正常運作,但當您將 Web API 應用程式發佈至生產 IIS 網頁伺服器時,可能會遇到 HTTP 405 錯誤。
HTTP 501 錯誤
- 表示伺服器上尚未實作特定功能。
- 通常表示您的 IIS 設定中沒有定義符合 HTTP 要求的處理常式:
- 可能表示 IIS 上未正確安裝某些內容或
- 某些專案已修改 IIS 設定,因此沒有定義支援特定 HTTP 方法的處理常式。
若要解決此問題,您必須重新安裝任何嘗試使用其沒有對應模組或處理常式定義的 HTTP 方法的應用程式。
摘要
當 Web 伺服器不允許要求 URL 的 HTTP 方法時,就會造成 HTTP 405 錯誤。 當特定動詞已定義特定處理常式,而且該處理常式會覆寫您預期處理要求的處理常式時,通常會看到此條件。