在c#中欺骗主机请求网页

我需要创建一个发送到我们网站的网页请求,但我也需要能够设置主机头信息。 我已经使用HttpWebRequest尝试了这个,但是Header信息是只读的(至少它的主机部分是)。 我需要这样做,因为我们想在用户可以之前执行页面的初始请求。 我们有10个负载均衡的Web服务器,因此我们需要从每个Web服务器请求该文件。

我尝试过以下方法:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm"); request.Headers.Set("Host", "www.mywebsite.com"); WebResponse response = request.GetResponse(); 

显然这不起作用,因为我无法更新标题,我不知道这是否确实是正确的方法。

虽然这是一个非常晚的答案,但也许有人可以从中受益

 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://192.168.1.1")); request.Headers.GetType().InvokeMember("ChangeInternal", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, request.Headers, new object[] {"Host","www.mysite.com"}); 

反思是你的朋友:)

我已经设法通过使用套接字找到更长的绕线路线。 我在IPEndPoint的MSDN页面中找到了答案:

 string getString = "GET /path/mypage.htm HTTP/1.1\r\nHost: www.mysite.mobi\r\nConnection: Close\r\n\r\n"; Encoding ASCII = Encoding.ASCII; Byte[] byteGetString = ASCII.GetBytes(getString); Byte[] receiveByte = new Byte[256]; Socket socket = null; String strPage = null; try { IPEndPoint ip = new IPEndPoint(IPAddress.Parse("10.23.1.93"), 80); socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); socket.Connect(ip); } catch (SocketException ex) { Console.WriteLine("Source:" + ex.Source); Console.WriteLine("Message:" + ex.Message); } socket.Send(byteGetString, byteGetString.Length, 0); Int32 bytes = socket.Receive(receiveByte, receiveByte.Length, 0); strPage = strPage + ASCII.GetString(receiveByte, 0, bytes); while (bytes > 0) { bytes = socket.Receive(receiveByte, receiveByte.Length, 0); strPage = strPage + ASCII.GetString(receiveByte, 0, bytes); } socket.Close(); 

我有一个问题,我使用的URL DNS有几个不同的IP地址,我想在主机中使用相同的DNS名称分别调用每个地址 – 解决方案是使用代理:

 string retVal = ""; // Can't change the 'Host' header property because .NET protects it // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); // request.Headers.Set(HttpRequestHeader.Host, DEPLOYER_HOST); // so we must use a workaround HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Proxy = new WebProxy(ip); using (WebResponse response = request.GetResponse()) { using (TextReader reader = new StreamReader(response.GetResponseStream())) { string line; while ((line = reader.ReadLine()) != null) retVal += line; } } return retVal; 

主机头由.NET自动设置为’url’,’ip’包含您要联系的Web服务器的实际地址(您也可以在此处使用dns名称)

我知道这是旧的,但我遇到了同样的问题,我找到了一个更好的解决方案,然后使用套接字或reflection……

我所做的是创建一个新的类,它从WebHeaderCollection开始,并绕过你在其中的内容validation:

 public class MyHeaderCollection:WebHeaderCollection { public new void Set(string name, string value) { AddWithoutValidate(name, value); } //or public new string this[string name] { get { return base[name]; } set { AddWithoutValidate(name, value); } } } 

以下是你如何使用它:

  var http = WebRequest.Create("http://example.com/"); var headers = new MyHeaderCollection(); http.Headers = headers; //Now you can add/override anything you like without validation: headers.Set("Host", http.RequestUri.Host); //or headers["Host"] = http.RequestUri.Host; 

希望这有助于任何人寻找这个!

我知道这是一个老问题,但是现在,你可以做到。

 HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm"); request.Host = "www.mywebstite.com"; WebResponse response = request.GetResponse(); 

“主机”标头受到保护,无法以编程方式进行修改。 我想解决这个问题,您可以尝试通过reflection绑定到WebRequest对象的私有“InnerCollection”属性,并在其上调用“Set”ar“Add”方法来修改Host标头。 我没试过这个,但是从快速查看Reflector中的源代码,我认为它很容易实现。 但是,绑定到框架对象的私有属性并不是完成任务的最佳方法。 :)只有你必须使用。

编辑:或者像链接问题中提到的其他人一样,只需打开一个套接字并手动快速“GET”。 如果你不需要修补其他东西,比如cookie或HttpWebRequest提供的任何其他细节,那应该是没有道理的。

好吧,有点研究结果如下:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384456

似乎MS 可能会在某些方面对此做些什么。

你可以使用我的解决方案解决这个问题,它发布在这里:

如何在HttpWebRequest中设置自定义“主机”标头?

这可以帮助您编辑主机头,并避免使用代理和直接套接字请求。

Necromancing。
对于仍然使用.NET 2.0的用户
事实上,如果你知道如何,这很容易。

问题是,您无法设置主机头,因为框架不会让您在运行时更改该值。 (.net framework 4.0+将允许您覆盖httpwebrequest中的主机)。

下一次尝试将使用reflection设置标题 – 如此处的顶部upvoted答案所示 – 来绕过它,这将允许您更改标题值。 但是在运行时,它会用url的主机部分覆盖这个值,这意味着reflection将不会给你带来任何东西,这就是为什么我理解为什么人们继续投票。

如果dns-name不存在,坦率地说,这是你想要首先执行此操作的唯一情况,你无法设置它,因为.NET无法解决它,你不能覆盖.NET DNS解析器。

但是你可以做的是设置一个webproxy与目标服务器完全相同的IP。

因此,如果您的服务器IP是28.14.88.71:

 public class myweb : System.Net.WebClient { protected override System.Net.WebRequest GetWebRequest(System.Uri address) { System.Net.WebRequest request = (System.Net.WebRequest)base.GetWebRequest(address); //string host = "redmine.nonexistantdomain.com"; //request.Headers.GetType().InvokeMember("ChangeInternal", // System.Reflection.BindingFlags.NonPublic | // System.Reflection.BindingFlags.Instance | // System.Reflection.BindingFlags.InvokeMethod, null, // request.Headers, new object[] { "Host", host } //); //server IP and port request.Proxy = new System.Net.WebProxy("http://28.14.88.71:80"); // .NET 4.0 only System.Net.HttpWebRequest foo = (System.Net.HttpWebRequest)request; //foo.Host = host; // The below reflection-based operation is not necessary, // if the server speaks HTTP 1.1 correctly // and the firewall doesn't interfere // https://yoursunny.com/t/2009/HttpWebRequest-IP/ System.Reflection.FieldInfo horribleProxyServicePoint = (typeof(System.Net.ServicePoint)) .GetField("m_ProxyServicePoint", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); horribleProxyServicePoint.SetValue(foo.ServicePoint, false); return foo; // or return request; if you don't neet this } } 

瞧,现在

 myweb wc = new myweb(); string str = wc.DownloadString("http://redmine.netexistantdomain.com"); 

如果28.14.88.71是具有基于虚拟名称的托管(基于http-host-header)的Web服务器,则会得到正确的页面。

现在,您对WebRequest和WebClient的原始问题都有正确的答案。 我认为使用自定义套接字执行此操作将是错误的方法,尤其是在应该使用SSL时,以及当实际解决方案如此简单时……