通过


对在 Visual Studio 中正常运行但在生产 IIS 服务器上出错的 Web API2 应用进行故障排除

本文档介绍如何对部署到生产 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 方法列表。
复制 移动 这两种方法与 WebDAV 一起使用,其用途是自我解释的。
MKCOL 此方法与 WebDAV 一起使用,用于在指定的 URI 上创建集合(例如目录)。
PROPFIND PROPPATCH 这两种方法与 WebDAV 一起使用,它们用于查询或设置 URI 的属性。
锁定解锁 这两种方法与 WebDAV 一起使用,用于在创作时锁定/解锁请求 URI 标识的资源。
补丁 此方法用于修改现有 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 客户端向 Web 服务器上的 Web API 应用程序的 URL 发送了有效的 JSON 请求,但服务器返回了一条 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 的无扩展名 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 方法,因此会发生冲突。 在此特定情况下,即使为包含 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 服务器。 此开发 Web 服务器是服务器产品中附带的完整 IIS 功能的缩减版本,此开发 Web 服务器包含为开发方案添加的一些更改。 例如,WebDAV 模块通常安装在运行完整版 IIS 的生产 Web 服务器上,尽管该模块可能未使用。 IIS(IIS Express)的开发版本会安装 WebDAV 模块,但有意注释掉 WebDAV 模块的条目,因此 WebDAV 模块永远不会加载到 IIS Express 上,除非专门更改 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 错误。 当为某个特定谓词定义了一个特定的处理器,并且这个处理器覆盖了你期望用来处理请求的处理器时,这种情况经常会发生。