我正在编写一个机器人程序,希望尽可能地模拟Firefox的行为。通过检查发送的标题,我发现了一处微小的差异,但我不知道该如何去除它:
Firefox使用以下保持连接标题:
Connection: keep-alive
虽然C#总是发送:
Connection: Keep-Alive
我知道这可能不重要,但我仍然想知道是否有任何方法或黑客方式可以修改标题为全小写字母。
你有什么想法吗?
我正在编写一个机器人程序,希望尽可能地模拟Firefox的行为。通过检查发送的标题,我发现了一处微小的差异,但我不知道该如何去除它:
Firefox使用以下保持连接标题:
Connection: keep-alive
虽然C#总是发送:
Connection: Keep-Alive
我知道这可能不重要,但我仍然想知道是否有任何方法或黑客方式可以修改标题为全小写字母。
你有什么想法吗?
request.Headers.GetType().InvokeMember(
"ChangeInternal",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
Type.DefaultBinder,
request.Headers,
new object[] { "Connection", "keep-alive" }
);
请确保不要在请求中实际设置KeepAlive属性。
Connection: keep-alive
是 Chrome 和 Firefox 浏览器的默认标头。
Connection: Keep-Alive
是 Internet Explorer 的默认标头。绝对是这样的。
Connection: Keep-Alive
是 HttpWebRequest 的默认标头。如果使用 HttpWebRequest,我认为编写类似于 IE 的机器人是最佳选择。
我也需要使用C#来完成这个任务,一直在尝试使用HttpWebRequest。我想调用一个非.NET SOAP Web服务,该服务期望Connection: keep-alive以小写形式出现。
我不想通过套接字编程来解决这个问题,如果您有任何关于如何解决这个问题的建议,那将非常有帮助。
我的调查结果如下:
当使用http协议版本1.1时,即使指定了属性,头部信息也不会被发送。
例如:
var request = (HttpWebRequest)WebRequest.Create(Endpoint);
request.KeepAlive = true;
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黑客入口的标题删除。
所以这仍然让我陷入困境。
除了在套接字级别进行操作之外,还有其他方法吗?是否有其他类或第三方库可以让我随意修改标题?
很抱歉这不是一个答案,但我还不能对你的问题发表评论。
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()) {
...
}