繁体   English   中英

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

[英]How to send lower-case Keep-Alive header through HttpWebRequest

我正在编写一个机器人,它应该尽可能地模仿 firefox。 通过检查它发送的标头,我发现了一个小区别,我不知道如何摆脱:

Firefox 使用以下 keep-alive 标头:

Connection: keep-alive

虽然 c# 总是发出:

Connection: Keep-Alive

我知道这可能无关紧要,但我仍然很想知道是否有任何方法/黑客可以将该标题修改为全部小写。

任何想法如何做到这一点?

在.net 4.0中,这有效:

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

请确保您没有在请求中实际设置KeepAlive属性

我还需要使用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攻击的标题。

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

除了进入套接字级别之外还有其他方法吗? 是否有其他类或第三方库允许我按照自己的意愿修改标题?

对不起,这不是答案,但我还不能评论你的问题。

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

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

Connection: Keep-Alive是HttpWebRequest的默认标头。 我认为如果使用HttpWebRequest,你应该编写像IE这样的机器人是最佳选择。

使用反射,您可以将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()) {
    ...
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM