2009-09-20 83 views
5

如何在HttpWebRequest中设置自定义主机头?我知道通常这个类不允许你这样做,但是反正用反射或类似的东西,而实际上并不需要我用TCPClient发送整个数据包?如何在HttpWebRequest中设置自定义“主机”标头?

+0

你想要在标题中更改什么?因为大部分标题参数可以通过属性间接修改 – 2009-09-20 12:46:32

+0

为什么你需要自己设置“主机”标题。如果您向“www.google.com”发出请求,它只会成为主机标题。 – 2009-09-20 12:54:22

+0

@Yannick主机和其他保留参数不能。 – 2009-09-20 17:36:03

回答

4

还有就是要做到这一点迂回的方式,如下所述:

http://blogs.msdn.com/feroze_daud/archive/2005/03/31/404328.aspx

然而,该框架的下一个版本(.NET Framework 4.0中)会更容易。

http://blogs.msdn.com/ncl/archive/2009/07/20/new-ncl-features-in-net-4-0-beta-2.aspx

希望这有助于。

+0

我见过那个页面,虽然在那个解决方法旁边有很多问题,但这是一个非常肮脏的解决方法:) – 2009-09-20 17:37:20

+2

耻辱我不使用看起来不错的.NET 4。 – 2009-09-20 18:05:29

1

您可以使用此技巧,设计用于在.net 3.5解决这个问题。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Net; 
using System.Reflection; 


namespace ConsoleApplication6 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://198.252.206.16"); 

      FieldInfo headersFieldInfo = request.GetType().GetField("_HttpRequestHeaders", System.Reflection.BindingFlags.NonPublic 
                | System.Reflection.BindingFlags.Instance 
                | System.Reflection.BindingFlags.GetField); 

      CusteredHeaderCollection WssHeaders = new CusteredHeaderCollection("stackoverflow.com"); 

      headersFieldInfo.SetValue(request, WssHeaders); 

      request.Proxy = null; 
      HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 

      StreamReader sr = new StreamReader(response.GetResponseStream()); 
      string result = sr.ReadToEnd(); 
      Console.WriteLine(result); 
      Console.ReadLine(); 

     } 
     public class CusteredHeaderCollection : WebHeaderCollection 
     { 
      public bool HostHeaderValueReplaced { get;private set; } 

      public string ClusterUrl { get; private set; } 

      public CusteredHeaderCollection(string commonClusterUrl) : base() 
      { 
       if (string.IsNullOrEmpty("commonClusterUrl")) 
        throw new ArgumentNullException("commonClusterUrl"); 

       this.ClusterUrl = commonClusterUrl; 
      } 

      public override string ToString() 
      { 
       this["Host"] = this.ClusterUrl; 
       string tmp = base.ToString(); 
       this.HostHeaderValueReplaced = true; 

       return tmp; 
      } 

     } 
    } 
} 
0

WebClient允许它。

var client = new WebClient(); 
client.Headers.Add("Host", WebHeader); 

我不能告诉你为什么。该文档明确指出主机是系统标题。

+0

这是因为它不起作用 - 异常主机头不能直接更改。 – 2016-12-19 13:15:40

+0

它的工作原理。我正在使用它,在生产 – Patrick 2017-01-08 23:42:41

+0

不起作用。 ArgumentException:必须使用appropiate属性修改此标头。 – Mikhail 2017-05-16 12:47:43

3

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

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

下一次尝试将设置带反射的标题,以避开它,这将允许您更改标题值。但是在运行时,它会用url的主机部分覆盖这个值,这意味着反射会给你带来什么。

如果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; 



     return request; 
    } 


    } 

,瞧,现在

myweb wc = new myweb(); 
string str = wc.DownloadString("http://redmine.non-existant-domain.com"); 

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

+0

不错,适用于.NET 2.0。很显然,如果你真的需要使用代理服务器,这将不起作用;)只需升级到.NET 4.5 - WebRequest和WebClient都不推荐使用。 – User1 2016-12-21 08:19:58

相关问题