【问题标题】:Handling 100-continue when redirecting a POST request from a Web API controller从 Web API 控制器重定向 POST 请求时处理 100-continue
【发布时间】:2014-12-08 13:01:51
【问题描述】:

我有一个ApiController,它通过 HTTP 的状态代码 307 重定向它来响应 POST 请求。它只使用来自标头的信息,因此此操作不需要请求的正文。这个动作相当于:

public HttpResponseMessage Post() {
    var url;
    // Some logic to construct the URL
    var response = new HttpResponseMessage(HttpStatusCode.TemporaryRedirect);
    response.Headers.Location = new System.Uri(url);
    return response;
}

这很简单,但我想做一个改进。请求正文可能包含大量数据,因此我想利用 HTTP 状态代码 100 来提高此请求的效率。使用现在的控制器,对话可能如下所示:

> POST /api/test HTTP/1.1
> Expect: 100-continue
> ...

< HTTP/1.1 100 Continue

> (request body is sent)

< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...

由于重定向操作不需要请求正文,我希望能够将对话缩短为:

> POST /api/controller HTTP/1.1
> Expect: 100-continue
> ...

< HTTP/1.1 307 Temporary Redirect
< Location: (the URL)
< ...

我花了一天的大部分时间研究如何做到这一点,但我无法提出解决方案。在我的研究中,我了解到:

  • ApiController 的操作执行时,100 Continue 已经发送。
  • ApiController 构造时,100 Continue 已经发送。
  • HttpApplicationPreRequestHandlerExecute事件被触发时,100 Continue响应尚未发送。
  • DelegatingHandler 执行时,100 Continue 已经被发送。

基于此,到目前为止我想出的最佳解决方案是创建一个HttpModule,它使用RequestContext 上的RouteData 来覆盖当相关ApiController 的接收者时的响应请求。然而,这远不是一个理想的解决方案,原因有很多(代码分离、没有利用 Web API 的参数绑定以及绕过ApiController 上的AuthorizeAttribute 中的额外逻辑)。

似乎必须有更好的解决方案,但我发现关于如何在 Web API 应用程序中正确处理 Expect: 100-continue 标头的信息很少。 实现此ApiController 以正确处理Expect: 100-continue 标头的最简单方法是什么?

【问题讨论】:

  • 您使用的是 IIS 7 吗?
  • WebAPI 无法处理此标头,因为它在 IIS 中在 WebAPI 不知情的情况下在内核级别进行透明处理。
  • @AndrewCounts ...我就是这么说的。
  • @K.AlanBates 是的,我只是同意你的看法。 :)
  • @AndrewCounts 陷阱

标签: c# asp.net iis asp.net-web-api2 http-status-code-100


【解决方案1】:

...你确定你需要这个优化吗?

如果您使用的是 IIS 6,您正在考虑进入 IIS 5 兼容模式并编写 ReadRawData/SendRawData ISAPI 过滤器。由于我的回复中进一步给出的原因,ISAPI 扩展是不可能的。 (如果您使用的是 IIS 5 或更低版本,愿上帝怜悯您的灵魂)

如果您使用的是 IIS 7+,您可能可以不用编写 IIS 本机模块。

您的想法是正确的,当涉及到控制器时,响应已经发送,因为 Web API 存在于 ASP.NET 中;此响应由 IIS 核心处理。

一些轻量级的阅读材料

HTTP.SYS IIS and the 100 Continue

王大卫

“100 continue”,如“400 Bad Request”或 Kernel Response Cache Hit,其特殊之处在于 HTTP.SYS 在内核模式下透明地处理它而不通知用户模式任何事情。此外,ISAPI 扩展无法交互任何响应输出 - 他们只能生成响应输出,看不到响应输出的结果。因此,ISAPI 扩展将永远无法与生成“100 继续”或“100 继续”响应的请求进行交互以抑制它们。

在 IIS6 上,将用户模式处理注入到这些 HTTP.SYS 的透明请求处理是在 IIS5 中运行 兼容模式并使用 ReadRawData/SendRawData ISAPI 过滤器。 ReadRawData 强制 HTTP.SYS 将原始数据从网络传送到 在将用户模式输出解析为之前进行过滤的用户模式 放入队列的 HTTP 请求。

当然,这种方法完全违背了运行IIS6的目的 使用应用程序池和进程隔离(这里的一个单一故障 过滤用户模式进程会停止整个服务器)......但就是这样 当客户端有问题时服务器端的妥协......

仅供参考:此方法不适用于 Vista Server/IIS7。 HTTP.SYS 将 不再将网络上的原始数据交给用户模式进行过滤 在解析之前,所以用户模式代码不可能知道 触发自动“100 continue”的请求发生了。


编辑

Haacked Http Web Request Expect 100 Continue

【讨论】:

  • 请求正文可能是几 MB 并且是通过蜂窝连接发送的,因此这种优化有点重要。如果重定向响应是从HttpApplicationPreRequestHandlerExecute 事件发送的,那么交换按预期运行--至少在我正在开发的IIS8 Express 服务器上。这让我相信,虽然 IIS 可能会发送 100-continue,但 ASP.NET 实际上能够在不触发 100-continue 的情况下发送响应。
  • 您可能希望向 WebSockets 发出升级请求,然后创建您自己的客户端-服务器握手协议来处理此请求。 Http Continuation 的重点是初始检查只是说“嘿,服务器。你在服务吗?”服务器以“yup. Continue”响应,客户端立即发送其请求正文。
  • RFC 2616 的第 8.2.3 节说,服务器可以用100 Continue 响应并读取请求正文最终状态代码。我对规范的解释是使用 307 状态码响应是有效的。
  • RFC 2616 已失效。您应该参考 RFC7231.6.2.1 以了解将来对 100 Continue 的任何引用。尊敬的,我相信您对规范的解释是不正确的。服务器可以响应 100 Continue,表示“客户端,您可以继续”,或者服务器将发送一个最终状态码,表示连接已关闭。 RFC7231.5.1.1 为 Expect 标头提供了额外的解释和说明。
  • 根据RFC 7231, section 5.1.1:“100-continue 期望通知收件人,客户端将在此请求中发送(可能很大)消息正文,并希望收到 100(继续)临时响应如果请求行和标头字段不足以导致立即成功、重定向或错误响应。" (强调我的)
【解决方案2】:

我假设您将浏览器重定向到同一解决方案中的另一个控制器。您可以直接在原始 url-address 中处理请求,而不是重定向。这样,客户端只需要发送一次请求而不会被重定向。

实现这一点的一种方法是编写自己的IHttpControllerSelector,它会根据请求标头将请求分配给正确的控制器。

如果您只想将自定义选择器分配给某些特定路线,您可能需要检查以下 SO 问题: ASP.NET Web API custom IHttpControllerSelector for a single route

【讨论】:

    猜你喜欢
    • 2023-03-28
    • 2016-01-27
    • 1970-01-01
    • 2017-12-27
    • 2018-11-26
    • 1970-01-01
    • 2018-02-22
    • 2021-12-20
    • 1970-01-01
    相关资源
    最近更新 更多