2008-12-11 50 views
12

我需要创建一个网页的请求传递到我们的网站,但我需要能够设置主机头信息。我已经尝试过使用HttpWebRequest,但标题信息是只读的(或至少它的主机部分是)。我需要这样做,因为我们想在用户可以之前执行页面的初始请求。我们有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(); 

显然,这是不行的,因为我无法更新标题,我不知道这是否是真的做的正确方法。

+0

这个问题是非常密切相关的http://stackoverflow.com/问题/ 323264/http-request-bypass-dns-net也许有人应该将它关闭为重复? – 2008-12-11 11:55:57

回答

9

我已经设法通过使用套接字找出更长的蜿蜒的路线。我发现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(); 
0

好吧,研究点点变成了这样:

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

似乎MS 可以在某些时候做点什么。

+0

我收到异常“ArgumentException:'主机'标题不能直接修改。参数名称:name”。我认为它是只读在HttpWebRequest类 – Xetius 2008-12-11 11:38:17

+0

的投票,因为这个答案不起作用。 – 2008-12-11 11:50:20

+0

创建新答案而不是取消删除并完全重写旧的答案不是更好吗? – 2008-12-11 13:04:42

0

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

编辑:或者像其他人提到的链接问题,只需打开一个套接字并手动执行一个快速的“GET”。如果你不需要修改其他的东西,比如cookies或者HttpWebRequest所提供的任何其他细节,那么应该不用理会。

2

我知道这是老了,但我碰到这个完全相同的问题来了,我找到了一个更好的解决这一然后使用套接字或反射...

我所做的就是创建一个从WebHeaderCollection durives并绕过验证一个新的类你坚持它里面什么:

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; 

希望这可以帮助任何人寻找这个!

4

我有一个问题,我使用的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; 

主机头由'url'自动设置。NET和“IP”包含您想联系(您可以在这里使用DNS名称太)

10

虽然这是一个非常晚的答案Web服务器的实际地址,也许有人可以得到它的好处

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"}); 

反射是你的朋友:)

1

我知道这是一个古老的问题,但这些天,你可以做。

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

Necromancing。
对于那些仍然使用.NET 2.0的人
事实上,如果你知道如何,它其实很简单。

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

下一次尝试将使用反射设置标头 - 如顶部upvoted答案中所示 - 解决它,这将允许您更改标头值。但在运行时,它会覆盖的URL的主机部分,这意味着反射会带给你什么都没有,这就是为什么我明白为什么人们保持投票这个这个值。

如果DNS名称不存在,这是坦率地说要在其中做这个摆在首位的唯一案例,你不能对它进行设置,因为.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是虚拟Web服务器基于名称的托管(基于http-host-header)。

现在您对WebRequest和WebClient的原始问题都有正确答案。我认为使用自定义套接字来做这将是错误的方法,特别是当应该使用SSL,并且当一个实际的解决方案是那么简单...