【问题标题】:C# - Connection: keep-alive Header is Not Being Sent During HttpWebRequestC# - 连接:在 HttpWebRequest 期间未发送 keep-alive 标头
【发布时间】:2011-11-19 11:44:03
【问题描述】:

我正在尝试使用我的 HttpWebRequest 发送以下标头:

Connection: keep-alive

但是,标头永远不会发送。 Fiddler2 显示,每当我在 Google Chrome 中请求页面时,都会发送标头。但是,我的应用程序出于某种原因拒绝发送此标头。

我已将KeepAlive 属性设置为true(无论如何默认为true),但标题仍然没有发送。

我正在尝试使用多个 HttpWebRequest 发送此标头,但它们基本上都是这样的:

HttpWebRequest logIn6 = (HttpWebRequest)WebRequest.Create(new Uri(responseFromLogIn5));
logIn6.CookieContainer = cookies;
logIn6.KeepAlive = true;
logIn6.Referer = "https://login.yahoo.com/config/login?.src=spt&.intl=us&.lang=en-US&.done=http://football.fantasysports.yahoo.com/";
logIn6.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1";
logIn6.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
logIn6.Headers.Add("Accept-Encoding:gzip,deflate,sdch");
logIn6.Headers.Add("Accept-Language:en-US,en;q=0.8");
logIn6.Headers.Add("Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3");
logIn6.AllowAutoRedirect = false;

HttpWebResponse logIn6Response = (HttpWebResponse)logIn6.GetResponse();
string responseFromLogIn6 = logIn6Response.GetResponseHeader("Location");

cookies.Add(logIn6Response.Cookies);

logIn6Response.Close();

有谁知道我必须做什么才能确保发送此标头?

来自 Chrome 的 Fiddler2 Raw:

GET xxx HTTP/1.1
Host: accounts.google.com
Connection: keep-alive
Referer: https://login.yahoo.com/config/login?.src=spt&.intl=us&.lang=en-US&.done=http://football.fantasysports.yahoo.com/
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: xxx

HTTP/1.1 302 Moved Temporarily
Set-Cookie: xxx
Set-Cookie: xxx
Location: xxx
Content-Type: text/html; charset=UTF-8
P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
Date: Sat, 17 Sep 2011 22:27:09 GMT
Expires: Sat, 17 Sep 2011 22:27:09 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Length: 2176
Server: GSE

我的应用程序中的 Fiddler2 Raw:

GET xxx HTTP/1.1
Referer: https://login.yahoo.com/config/login?.src=spt&.intl=us&.lang=en-US&.done=http://football.fantasysports.yahoo.com/
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Host: accounts.google.com

HTTP/1.1 302 Moved Temporarily
Location: xxx
Content-Type: text/html; charset=UTF-8
Date: Sun, 18 Sep 2011 00:05:40 GMT
Expires: Sun, 18 Sep 2011 00:05:40 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Content-Length: 573
Server: GSE

我正在尝试让第二个 Fiddler2 原始信息看起来像第一个 Fiddler2 原始信息。

【问题讨论】:

  • Http 1.1 自动使用 Keep-alive,所以我觉得 keep-alive 头是多余的。 HttpWebRequest 确实发送 Connection: close 命令来显式关闭连接。
  • Keep-Alive 头不是多余的,因为它控制了持久连接上的超时和请求参数的数量。如果设置了 Keep-Alive,Connection 也应该设置为 Keep-Alive,否则参数将被忽略。显然HttpWebRequest 无法直接将这些标头设置为正确的值 - 他们将 KeepAlive 设为布尔值(不应该如此)并且设置 Connection 只会引发异常。微软把这个搞砸了。

标签: c# http https httpwebrequest http-headers


【解决方案1】:

你做得对。该代码应导致添加以下标头:

Connection: Keep-Alive

如果您没有看到此标头,请发布您用于从 Fiddler 发送请求和原始输出的代码。您也可以忽略这一点,因为 HTTP 1.1 连接是 keep-alive by default

更新:看起来 .NET 只为第一个 (!) 请求显式设置 Keep-Alive。对同一主机/url 的进一步请求将不会有此标头,可能是因为底层 tcp 连接已被重用。

【讨论】:

  • 查看上次更新。检查第一个请求是否有 Keep-Alive 和后续没有它。
  • 啊,这很有道理。我的第一个连接确实发送了标题。对不起,我应该提到这一点。但是,我不会向同一个主机/url 发出进一步的请求。此外,在发送第一个 Keep-Alive 标头后,我得到了这个响应标头:Connection: close。这不是意味着 TCP 连接被关闭了吗?
【解决方案2】:

我遇到了同样的问题:Connection: Keep-Alive 标头除了第一个请求外没有发送,如果我访问的服务器丢失,我不会给我正确的响应。所以,这是我对这个问题的解决方法:

首先将HttpWebRequest 实例的ProtocolVersion 属性设置为HttpVersion.Version10。除了 http 命令将变为 GET xxx HTTP/1.0 之外,它可以工作并且只使用公共 API。

第二种方式使用反射来修改HttpWebRequest实例的内部属性ServicePoint.HttpBehaviour,像这样:

var req = (HttpWebRequest)WebRequest.Create(someUrl);

var sp = req.ServicePoint;
var prop = sp.GetType().GetProperty("HttpBehaviour", 
                        BindingFlags.Instance | BindingFlags.NonPublic);
prop.SetValue(sp, (byte)0, null);

req.GetResponse().Close();

希望这会有所帮助。

【讨论】:

  • 好的。这行得通,虽然我不能停止觉得这是对一些愚蠢的 .net 错误的修复。非常感谢!我浪费了一天时间试图解决 HttpWebRequest 的问题!
【解决方案3】:

下载HttpWebRequest 源代码后,注意到每个属性都会检查一些已知的HeaderCollection 标头。为了摆脱对那个集合做一些反射的事情,让它工作

var webRequest = (HttpWebRequest) WebRequest.Create(url);
webRequest.Headers.GetType().InvokeMember("ChangeInternal",
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
    Type.DefaultBinder, webRequest.Headers, new object[] {name, value}
);

【讨论】:

    【解决方案4】:

    这个问题我纠结了半天!亲爱的老提琴手(我的守护天使)无意中成为问题的一部分:

    每当我使用 Fiddler 监控测试我的 HTTP POST 时 - 问题都不会出现 每当我在 Fiddler 监控关闭的情况下测试我的 HTTP POST 时 - 问题确实出现了

    我的 POSTS 是使用协议 1.1 发送的,并且在初始连接后,Keep-Alive 被忽略/冗余/为什么。即我可以在第一个 POST 的标题中看到它(通过 Fiddler!),但在随后的 POST 中看不到它,尽管使用了相同的代码。嘿嘿...

    但是远程服务器只有在发送 Keep-Alive 时才会响应。现在我无法证明这一点,但我怀疑 Fiddler 监视连接导致远程服务器认为或相信连接仍然处于活动状态(尽管在我第一次 POST 后没有发送 Keep-Alives)并正确响应。正如我所说,在我关闭 Fiddler 的那一刻,没有 Keep-Alives 导致远程服务器对我超时..

    我实现了上述 1.0 解决方案,并且我的 POSTS 现在可以工作,无论是否打开或关闭 Fiddler。希望这可以帮助其他人卡在某个地方...

    【讨论】:

    【解决方案5】:

    我知道这个问题的答案,因为我遇到了同样的问题,并设法通过继承 webclient 并覆盖它的 Get Web Request 方法来解决它。

    请看下面的代码:

        public class CookieAwareWebClient : WebClient
    {
        public CookieContainer CookieContainer { get; set; }
    
        public CookieAwareWebClient()
            : this(new CookieContainer())
        { }
    
        public CookieAwareWebClient(CookieContainer c)
        {
            this.CookieContainer = c;
        }
    
        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            var castRequest = request as HttpWebRequest;
    
            if (castRequest != null)
            {
                castRequest.KeepAlive = true; //<-- this what you want! The rest you don't need. 
                castRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
                castRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36";
                castRequest.Referer = "https://www.jobserve.com/gb/en/Candidate/Login.aspx?url=48BB4C724EA6A1F2CADF4243A0D73C13225717A29AE8DAD6913D";
                castRequest.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
                castRequest.Headers.Add("Accept-Language", "en-GB,en-US;q=0.8,en;q=0.6");
                castRequest.CookieContainer = this.CookieContainer;
            }
    
            return request;
        }
    }
    

    如您所见,我不仅启用了 keep-alive,而且还使用了 cookie 和其他标头!

    希望对你有帮助!

    基兰

    【讨论】:

    • 这不起作用。在代码中放一个断点,你会看到“.KeepAlive”属性已经为真,但是Conection: Keep-Alive并没有随请求一起发送。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 2012-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    相关资源
    最近更新 更多