針對在 Visual Studio 中運作的 Web API2 應用程式進行疑難排解,並在生產 IIS 伺服器上失敗

本檔說明如何針對部署至生產 IIS 伺服器的 Web API2 應用程式進行疑難排解。 其可解決常見的 HTTP 405 和 501 錯誤。

本教學課程中使用的軟體

Web API 應用程式通常會使用數個 HTTP 動詞命令:GET、POST、PUT、DELETE,有時也會使用 PATCH。 也就是說,開發人員可能會在其生產 IIS 伺服器上由另一個 IIS 模組實作這些動詞的情況,這會導致在 Visual Studio 或開發伺服器上正常運作的 Web API 控制器會在部署至生產 IIS 伺服器時傳回 HTTP 405 錯誤。

造成 HTTP 405 錯誤的原因

瞭解如何針對 HTTP 405 錯誤進行疑難排解的第一個步驟是瞭解 HTTP 405 錯誤實際上的意義。 HTTP 的主要控管檔是 RFC 2616,它會將 HTTP 405 狀態碼定義為 「不允許的方法」,並進一步描述此狀態碼為「要求 URI 所識別的資源不允許在Request-Line中指定的方法」的情況。換句話說,HTTP 用戶端所要求的特定 URL 不允許 HTTP 動詞命令。

簡短檢閱以下是 RFC 2616、RFC 4918 和 RFC 5789 中所定義的幾個最常使用的 HTTP 方法:

HTTP 方法 描述
GET 這個方法可用來從 URI 擷取資料,而且可能是最常使用的 HTTP 方法。
HEAD 這個方法與 GET 方法非常類似,不同之處在于它實際上不會從要求 URI 擷取資料 , 它只會擷取 HTTP 狀態。
POST 這個方法通常用來將新資料傳送至 URI;POST 通常用來提交表單資料。
PUT 這個方法通常用來將原始資料傳送至 URI;PUT 通常用來將 JSON 或 XML 資料提交至 Web API 應用程式。
刪除 這個方法可用來從 URI 移除資料。
OPTIONS 這個方法通常用來擷取 URI 支援的 HTTP 方法清單。
COPY MOVE 這兩種方法搭配 WebDAV 使用,其用途是自我說明。
MKCOL 此方法會與 WebDAV 搭配使用,並用來建立集合 (例如指定 URI 上的目錄) 。
PROPFIND PROPPATCH 這兩種方法會與 WebDAV 搭配使用,並用來查詢或設定 URI 的屬性。
鎖定解除鎖定 這兩種方法會與 WebDAV 搭配使用,並用於在撰寫時鎖定/解除鎖定要求 URI 所識別的資源。
PATCH 這個方法可用來修改現有的 HTTP 資源。

當其中一個 HTTP 方法設定為在伺服器上使用時,伺服器會回應 HTTP 狀態和其他適用于要求的資料。 (例如,GET 方法可能會收到 HTTP 200 OK 回應,而 PUT 方法可能會收到 HTTP 201 Created 回應。)

如果未將 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 服務器上的 Web API 應用程式的 URL,但伺服器傳回 HTTP 405 錯誤訊息,表示 URL 不允許 PUT 方法。 相反地,如果要求 URI 不符合 Web API 應用程式的路由,伺服器會傳回 HTTP 404 找不到 錯誤。

解決 HTTP 405 錯誤

有數個原因導致不允許特定 HTTP 動詞命令,但有一個主要案例是 IIS 中此錯誤的前置原因:針對相同的動詞/方法定義多個處理常式,而其中一個處理常式會封鎖預期的處理常式來處理要求。 藉由說明,IIS 會根據 applicationHost.configweb.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 處理常式和用於 Web API) 之 ASP.NET (的擴充功能 URL 處理常式會明確定義為個別的 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 方法,因此會發生衝突。 在此特定情況下,即使 WebDAV 已針對包含 Web API 應用程式的網站停用 WebDAV,IIS 還是會定義並載入 WebDAV 處理常式。 在處理 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 Web 服務器時,可能會遇到 HTTP 405 錯誤。

HTTP 501 錯誤

  • 表示伺服器上尚未實作特定功能。
  • 通常表示您的 IIS 設定中沒有定義符合 HTTP 要求的處理常式:
    • 可能表示 IIS 上未正確安裝某些專案或
    • 某些專案已修改 IIS 設定,因此沒有定義支援特定 HTTP 方法的處理常式。

若要解決此問題,您必須重新安裝任何嘗試使用其沒有對應模組或處理常式定義的 HTTP 方法的應用程式。

總結

當 Web 服務器不允許要求 URL 的 HTTP 方法時,就會造成 HTTP 405 錯誤。 當特定動詞已定義特定處理常式,而且該處理常式會覆寫您預期處理要求的處理常式時,通常會看到此條件。