HTTPWebRequest.GetResponse()在透明代理中进行身份验证的请求失败

13

我们正在使用 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需要完全重启。

查看网络捕获,发现两个请求最初都是相同的,首次未经身份验证的请求被发送,服务器回复后,但失败的请求在初始回复中间发送第二个已认证的请求,就好像它正在忽略Content-Length标头(这是正确的)。 然后它接收到了其余的初始回复并由于协议错误而失败。

Wireshark capture

然而,客户端(HTTPWebRequest)似乎不会干净地关闭连接。

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

我已将问题代码缩小到最小,并使用MSDN示例进行了复制,但是否有人知道这是已知问题还是我们(.NET或Squid)配置方面的问题?


不确定问题是否出在这里,但你是否确保在完成后关闭了你的StreamReader? - Jon Senchyna
我不知道这个。谢谢你告诉我。既然目标应用程序是你的,那么ContentLength是如何设置的呢?我知道我在过去的一个项目中曾经遇到过问题,尝试自己生成正确的ContentLength,因为它是响应字节数而不是字符数。 - Jon Senchyna
这是将“纯文本”(本地代码页)转换为字节数组,然后将其传递给创建标题的函数,并从该字节数组中获取大小。不过,您已促使我尝试在不同类型的服务器上进行测试,以完全消除我们的代码... - Deanna
希望这对你有用。很抱歉我不能帮你找到根本问题。我想我以前尝试过类似的方法,但由于大小与字节数组的大小不同而出现了问题。我不记得我当时是怎么解决的了。 - Jon Senchyna
你能绕过代理进行身份验证,然后在实际需要缓存内容时启用流量通过吗? - EkoostikMartin
显示剩余11条评论
3个回答

1

由于它只在第二次失败,那么会

request.KeepAlive = false;

有何不同?


它确实可以解决问题,但我不愿意将其作为永久性的解决方案,因为这更像是一个变通方法,而不是对初始问题的修复。无论如何,我会接受它。 - Deanna

0

我没有使用NTLM身份验证。NetworkCredential对象是方案不可知的。代理根本没有经过身份验证,只有我们请求的HTTP资源使用基本身份验证。 - Deanna

0

尝试使用身份验证

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

request.GetResponse();之前

这对我有效。起初我试图将整个字符串放进去,但却不起作用!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接