如何通过HttpWebRequest发送小写Keep-Alive头信息

3

我正在编写一个机器人程序,希望尽可能地模拟Firefox的行为。通过检查发送的标题,我发现了一处微小的差异,但我不知道该如何去除它:

Firefox使用以下保持连接标题:

Connection: keep-alive

虽然C#总是发送:

Connection: Keep-Alive

我知道这可能不重要,但我仍然想知道是否有任何方法或黑客方式可以修改标题为全小写字母。

你有什么想法吗?

4个回答

6
在 .net 4.0 中,这个代码可以正常工作:
request.Headers.GetType().InvokeMember(
    "ChangeInternal",
    BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
    Type.DefaultBinder, 
    request.Headers, 
    new object[] { "Connection", "keep-alive" }
);

请确保不要在请求中实际设置KeepAlive属性。


谢谢,这刚刚救了我的一天 :) - MeeKaaH
这将导致头部设置为keep-alive,Keep-Alive,但它可能仍然工作得更好。 - Erwin Mayer
即使您将KeepAlive属性设置为false,也是这样吗? - Grubsnik

1
"

Connection: keep-alive 是 Chrome 和 Firefox 浏览器的默认标头。

Connection: Keep-Alive 是 Internet Explorer 的默认标头。绝对是这样的。

Connection: Keep-Alive 是 HttpWebRequest 的默认标头。如果使用 HttpWebRequest,我认为编写类似于 IE 的机器人是最佳选择。

"

1

我也需要使用C#来完成这个任务,一直在尝试使用HttpWebRequest。我想调用一个非.NET SOAP Web服务,该服务期望Connection: keep-alive以小写形式出现。

我不想通过套接字编程来解决这个问题,如果您有任何关于如何解决这个问题的建议,那将非常有帮助。

我的调查结果如下:

当使用http协议版本1.1时,即使指定了属性,头部信息也不会被发送。

例如:

var request = (HttpWebRequest)WebRequest.Create(Endpoint); 
request.KeepAlive = true;

解决方案是使用System.Reflection来修改httpBehaviour,这将意味着发送Keep-Alive。这将在每个请求上发送一个初始的大写K和A“Keep-Alive”。
var sp = request.ServicePoint; 
var prop = sp.GetType().GetProperty("HttpBehaviour", BindingFlags.Instance | BindingFlags.NonPublic);
prop.SetValue(sp, (byte)0, null);

我尝试使用System.Reflection来修改标题。以下代码将正确地以小写形式添加标志:

request.Headers.GetType().InvokeMember("ChangeInternal", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, Type.DefaultBinder, request.Headers, new object[] { "Connection", "keep-alive" });

然而,在我调用GetResponse的时候

var response = (HttpWebResponse)request.GetResponse()

头部信息被清除了。查看HttpWebRequest.cs的源代码,发现这是在将头部信息发送到网络之前发生的。

    //
    // The method is called right before sending headers to the wire*
    // The result is updated internal _WriteBuffer
    //
    // See ClearRequestForResubmit() for the matching cleanup code path.
    // 
    internal void SerializeHeaders() {

    ....
    ....

        string connectionString = HttpKnownHeaderNames.Connection; 
        if (UsesProxySemantics || IsTunnelRequest ) { 
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.Connection);
            connectionString = HttpKnownHeaderNames.ProxyConnection; 
            if (!ValidationHelper.IsBlankString(Connection)) {
                _HttpRequestHeaders.AddInternal(HttpKnownHeaderNames.ProxyConnection, _HttpRequestHeaders[HttpKnownHeaderNames.Connection]);
            }
        } 
        else {
            _HttpRequestHeaders.RemoveInternal(HttpKnownHeaderNames.ProxyConnection); 
        } 

RemoveInternal还将使用Reflection黑客入口的标题删除。

所以这仍然让我陷入困境。

除了在套接字级别进行操作之外,还有其他方法吗?是否有其他类或第三方库可以让我随意修改标题?

很抱歉这不是一个答案,但我还不能对你的问题发表评论。


最终我放弃了。在C#中这根本做不到。我和我试图连接的服务的开发人员交谈,猜猜怎么着 - 他们在他们的那一边修复了BUG。 - Arsen Zahray

0
使用反射,您可以将 WebHeaderCollection 的内部 NameValueCollection 替换为自定义实现,例如以下内容:
// When injected into a WebHeaderCollection, ensures that
// there's always exactly one "Connection: keep-alive" header.
public class CustomNameValueCollection : NameValueCollection {

    private const BindingFlags allInstance =
        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

    private static readonly PropertyInfo innerCollProperty =
        typeof(WebHeaderCollection).GetProperty("InnerCollection", allInstance);

    private static readonly FieldInfo innerCollField =
        typeof(WebHeaderCollection).GetField("m_InnerCollection", allInstance);

    public static void InjectInto(WebHeaderCollection coll) {
        // WebHeaderCollection uses a custom IEqualityComparer for its internal
        // NameValueCollection. Here we get the InnerCollection property so that
        // we can reuse its IEqualityComparer (via our constructor).
        var innerColl = (NameValueCollection) innerCollProperty.GetValue(coll);
        innerCollField.SetValue(coll, new CustomNameValueCollection(innerColl));
    }

    private CustomNameValueCollection(NameValueCollection coll) : base(coll) {
        Remove("Connection");
        base.Add("Connection", "keep-alive");
    }

    public override void Add(string name, string value) {
        if (name == "Connection") return;
        base.Add(name, value);
    }
}

使用方法如下:

var request = (HttpWebRequest) WebRequest.Create("https://www.google.com/");
CustomNameValueCollection.InjectInto(request.Headers);
using (var response = request.GetResponse()) {
    ...
}

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