26

我遇到了一个大型内部企业基于 Web 的应用程序,它在 IIS6 上运行 ASP.NET 3.5,生成 401 个“未经授权”响应,然后是 200 个“Ok”响应(如 Fiddler 所述)。我知道为什么会发生这种情况(集成身份验证强制浏览器重新发送凭据),但我正在寻找一些关于如何最小化或消除这种情况的想法。有问题的应用程序在 WAN 中运行,一些用户遇到高达 250 毫秒的延迟,因此强制执行后续请求可能会对页面加载时间产生显着影响,尤其是当页面上有许多级联下拉列表时。

应用程序的用户是托管桌面环境的内部用户,因此从部署的角度来看,强制浏览器在第一个请求时发送凭据的机制(这甚至可能吗?)是可能的。这适用于需要用户身份的页面,但对于不需要身份验证的资源(WebResource.axd、ScriptResource.axd 和一些自定义 Web 服务),允许匿名身份验证是可能的。我已经在 web.config 中查看了基于每个位置的定义,但结果好坏参半(仍然有许多 401 响应)。

对于处理这种情况的“最佳实践”的任何指导,我将不胜感激。有很多资源可以确定问题,但我发现没有一个资源可以提供可行的解决方案。

谢谢!

编辑:不需要身份验证的资源(即用于级联下拉列表的 Web 服务)可以通过向 Web 配置添加位置条目来匿名请求,但我还没有找到经过身份验证的资源的答案。

4

5 回答 5

17

不幸的是,这是HTTP NTLM 身份验证方案的产物。

简而言之,浏览器(Internet Explorer 或其他)根本不知道它需要进行身份验证,直到它被包含WWW-Authenticate响应标头的 401 响应退回。

在这种情况下WWW-Authenticate: NTLM——很烦人——它需要在一个持久连接上完成两个401 响应,并且一旦 HTTP 持久连接关闭,就必须重复这个过程。因此,即使您能够让浏览器发起一个盲目尝试 NTLM 的请求,也无法从事务中删除至少一个 401 响应。

我认为你最好的选择是最大化持续连接在空闲时保持打开的时间。

于 2009-04-30T00:37:45.787 回答
3

CSCRIPT.EXE c:\inetpub\adminscripts\ADSUTIL.VBS SET W3SVC/AuthPersistSingleRequest FALSE

将大大减少401的数量。

于 2010-08-17T23:09:15.847 回答
0

我相信您可以说服 Firefox 通过“about:config”设置自动将 NTLM 凭据发送到一组列入白名单的域 - 使用“network.automatic-ntlm-auth.trusted-uris”设置。虽然我自己没有尝试过。我不确定 Internet Explorer 是否有任何等价物。

不幸的是,如果您使用的是 Kerberos 之类的其他东西,似乎没有办法避免 401。

于 2009-03-29T08:22:48.150 回答
0

如果 401 引起的延迟太长,您可能需要考虑表单身份验证。用户必须显式登录,但只需登录一次。然后,您可以使用 cookie 或无 cookie 方案并在第一次尝试时获得响应。

我想如果您有级联下拉菜单并且您的初始页面加载填充一个值,该值导致 POST 获取下一个列表,设置该值,另一个 POST 再次获取下一个列表,我想页面加载会很慢,依此类推。如果是这种情况,也许您需要在第一次往返时填充所有这些下拉列表,而不是等待 POST 响应。

于 2009-05-01T05:16:16.827 回答
0

TL;DR 我将 HTTP 标头信息放在 HTTP 正文中

我的例子是 Angular,但任何 TypeScript/JavaScript(框架)都可能有同样的问题。

在对我的后端 API 进行 HTTP 发布调用时,它需要带有登录用户信息的标头,我将我的 HTTP 标头添加到我的 HTTP 正文应该是并且标头为空的位置。

问题

  markInstructionAsCompleted(visitScheduleId: string, instructionId: number) {
    return this.http.post(`${environment.apiUrl}/VisitInstructions/schedule/${visitScheduleId}/done/${instructionId}`, this.getHeaderWithAuthorization());
  }

解决方案,请注意 HTTP post 调用中添加了第二个参数,即null

  markInstructionAsCompleted(visitScheduleId: string, instructionId: number) {
    return this.http.post(`${environment.apiUrl}/VisitInstructions/schedule/${visitScheduleId}/done/${instructionId}`, null, this.getHeaderWithAuthorization());
  }
于 2020-04-30T11:17:53.693 回答