HTTPWebRequest.GetResponse() 通过透明代理验证请求失败

Posted

技术标签:

【中文标题】HTTPWebRequest.GetResponse() 通过透明代理验证请求失败【英文标题】:HTTPWebRequest.GetResponse() failing with authenticated requests through a transparent proxy 【发布时间】:2012-06-14 14:29:14 【问题描述】:

我们正在使用 HTTPWebRequest 对象向我们的应用程序发出 HTTP 请求,当请求需要身份验证并且存在透明代理 (Squid 3.1.10) 时,我们遇到了问题。

string url = "http://www.icode.co.uk/test/auth.php";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = new NetworkCredential("username", "password");

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);

MessageBox.Show(reader.ReadToEnd());

reader.Close();
stream.Close();
response.Close();

我们的原始代码使用了出现同样问题的 WebClient 类。

此代码第一次运行时,它会正确显示结果。 当代码第二次运行时,它会在 GetResponse() 行失败,并显示:

System.Net.WebException was unhandled
  Message="The server committed a protocol violation. Section=ResponseStatusLine"
  Source="System"
  StackTrace:
       at System.Net.HttpWebRequest.GetResponse()
       at Dummy.DummyForm.button1_Click(Object sender, EventArgs e) in H:\Trial\Dummy\DummyForm.cs:line 42
       at ...

在 Windows 7 上,重新启动进程会使其恢复并运行一次,但 Server 2003 需要完全重新启动。

查看network capture,两个请求一开始是相同的,发送初始未经身份验证的请求并且服务器回复,但失败的请求在初始回复中间发送第二个经过身份验证的请求,就好像它忽略了Content-Length 标头(正确)。然后它会收到初始回复的其余部分,并因协议错误而失败。

客户端 (HTTPWebRequest) 并没有完全关闭连接,这似乎很奇怪。

当代理未使用时(非端口 80 或内部流量),所有请求都按预期工作。当没有身份验证时,它也可以工作,因为它只发出单个请求。

我已经将问题代码减少到最低限度并使用 MSDN 示例进行了重现,但有人知道这是已知问题还是我们(.NET 或 Squid)配置中的问题?

【问题讨论】:

不确定这是否是问题所在,但您是否确保完成后关闭 StreamReader? 感谢您添加屏幕截图。您是否从其中的第一个 GET 中删除了授权信息,或者它没有包含任何信息? 我已经删除了我的答案,因为很明显它不适用。 @JonSenchyna 它永远不会,那是normal HTTP behaviour。首先发送未经身份验证的请求,然后在质询中发送正确的详细信息。 我不知道。谢谢你让我知道。既然目标应用程序是你的,那么 ContentLength 是如何设置的?我知道我过去在尝试自己生成正确的 ContentLength 时遇到了问题,因为它是响应的字节数而不是字符数。 【参考方案1】:

既然只是第二次失败,会不会

request.KeepAlive = false;

有所作为?

【讨论】:

它does 但我不愿意将其用作永久性修复,因为它更多的是一种解决方法,而不是最初问题的修复。无论如何我都会接受的【参考方案2】:

我认为 NTLM 身份验证 (NetworkCredential) 不能与 SQUID 的透明代理功能同时工作。 :-(

http://www.squid-cache.org/mail-archive/squid-users/201110/0025.html

您可以尝试其他身份验证方案吗?

【讨论】:

我没有使用 NTLM 身份验证。 NetworkCredential 对象与方案无关。代理根本没有经过身份验证,只是我们请求的 HTTP 资源,使用基本身份验证。【参考方案3】:

尝试验证自己,使用

request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(username + ":" + password));

request.GetResponse();之前

这对我有用。首先我尝试自己放入整个字符串,但没有奏效!

【讨论】:

以上是关于HTTPWebRequest.GetResponse() 通过透明代理验证请求失败的主要内容,如果未能解决你的问题,请参考以下文章