我目前正在开发一个涉及使用XMLHttpRequest上传异步文件的Web应用程序。
使用NTLM身份验证时(这有点必要),异步POST最终会被发送两次。第一次响应是401,第二次是200.由于NTLM的挑战/响应性质,这是我的预期,但我想知道是否有办法避免发送文件数据两次(特别是因为上传的文件可能非常大),可能会以某种方式先发送一个空请求,然后在发送实际数据之前触发401。
答案 0 :(得分:1)
在浏览器中,由于HTTP和NTLM身份验证协议的性质,您无法避免这种情况。
但是,我认为整个文件的数据实际上并没有被发送两次。
我将以下内容发送到IIS 7.5上受NTLM保护的文件:
POST /test/upload HTTP/1.1
Host: localhost
Content-Length: 5
请注意,我实际上并没有发送任何内容,只有完整的标题。但是,IIS 立即响应:
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM
Date: Thu, 10 Jan 2013 05:17:58 GMT
Content-Length: 6277
...
这意味着如果我是浏览器上传大文件,那么在转移很多字节之前我会被切断。我假设(希望)任何表现良好的浏览器都会放弃文件上传并开始HTTP身份验证。
你可能值得花时间去看看Wireshark这样的东西,看看究竟是什么在线上。 (请记住使用不同的浏览器进行测试!)不要信任浏览器中的开发人员工具,也不要使用像Fiddler这样的调试代理。 (事实上,如果您正在使用Fiddler,那可能实际上是问题:它在将任何发送到服务器之前缓冲整个请求。)
如果您确实发现整个文件确实上传了两次(可能是旧版本的IIS没有立即发送401
?),请考虑事情必须如何发生:
用户提交上传,导致浏览器向服务器发出POST
请求。由于浏览器无法知道URL是否需要身份验证,因此它只会关闭完整请求。
POST /upload HTTP/1.1
Content-Type: mutlipart/form-data
Content-Length: 1024
...
服务器可能会立即使用401
进行响应,但行为不端的用户代理仍然会传输整个请求。
请求完成后,浏览器会看到401
,我们就会开始NTLM dance。客户端必须发出带有Type 1消息的新请求,服务器以另一个401
响应,这次包含Type 2消息,最后客户端发出第三个请求使用包含实际凭据的Type 3消息。
由于客户端知道第二个请求在NTLM协商中保证是另一个401
,因此它知道它可以跳过实体的传输(表单数据)。但是,它必须在第三个请求上第二次发送发布数据,因为我们必须假设服务器丢弃了原始请求数据。
我们的文件终于上传了! (但它必须传输两次。)
因此,虽然我认为您实际上看不到使用NTLM身份验证的完整双重上传问题,但您可能仍希望消除这种可能性。以下是我要解决的问题:
将NTLM身份验证区域的上传网址移到之外。在上载页面(经过NTLM身份验证)上,使用会话cookie(在加载页面时设置)或发出令牌 - 隐藏字段中的GUID就足够了。
脚本接收上传可以拒绝任何没有有效会话和/或令牌的请求。
如果您使用NTLM凭据作为授予对NTFS资源的访问权限的机制,则可以将上载写入匿名可写的临时文件夹,完成后,将请求重定向到第二个受NTLM保护的脚本,该脚本会移动文件到目的地。
答案 1 :(得分:0)
不确定您的实施,但看起来其他人遇到过与cURL和NTLM类似的问题。根据以下链接,您可能会首先想出任何空的请求。
POST文件两次通过NTLM-proxy
http://curl.haxx.se/mail/lib-2007-01/0040.html
我正在使用curl_formadd和POST方法通过代理发送文件 NTLM-auth的。看看ProgressFunction,我看到我的文件发送了两次 (可能是因为NTLM特有的)。我是对还是不对?
你是对的。因为我们,在使用NTLM时没有办法避免这种情况 一旦开始转移,就无法中止转移。
使用NTLM / Negotiate代理身份验证进行文件上载的不同行为
http://curl.haxx.se/mail/archive-2012-11/0013.html