2009-09-20 12 views
5

Comment puis-je définir un en-tête Host personnalisé dans HttpWebRequest? Je sais que normalement cette classe ne vous permet pas de le faire mais est-ce qu'il y a de toute façon à utiliser la réflexion ou quelque chose comme ça sans réellement besoin de moi pour envoyer le paquet entier avec TCPClient?Comment définir l'en-tête "Host" personnalisé dans HttpWebRequest?

+0

Que voulez-vous changer exactement dans l'en-tête? Parce que la plupart des paramètres d'en-tête peuvent être modifiés indirectement par les propriétés –

+0

Pourquoi avez-vous besoin de définir l'en-tête "Hôte" par vous-même. Si vous faites une demande à 'www.google.com', il devient simplement l'en-tête de l'hôte. –

+0

@Yannick Host et d'autres paramètres réservés ne peuvent pas. –

Répondre

4

Il y a une façon détournée pour ce faire, comme décrit ici:

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

Cependant, la prochaine version du cadre (.NET Framework 4.0) sera plus facile.

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

Hope this helps.

+0

J'ai vu cette page bien qu'il y ait beaucoup de problèmes dans cette solution de contournement à côté de cela c'est une solution de contournement vraiment sale :) –

+2

Dommage que je n'utilise pas .NET 4 qui semble bon. –

1

Vous pouvez utiliser ce hack, conçu pour résoudre ce problème dans .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 le permet.

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

Je ne pourrais pas vous dire pourquoi. La documentation indique clairement que Host est un en-tête système.

+0

En effet, cela ne fonctionne pas - l'en-tête de l'hôte d'exception ne peut pas être modifié directement. –

+0

Cela fonctionne. Je l'utilise, en production – Patrick

+0

Ne fonctionne pas. ArgumentException: cet en-tête doit être modifié avec la propriété appropriée. – Mikhail

3

Nécromage.
Pour ceux qui sont encore sur. NET 2.0
C'est en fait assez facile, si vous savez comment.

Le problème est que vous ne pouvez pas définir l'en-tête de l'hôte car le framework ne vous laissera pas modifier la valeur au moment de l'exécution. (.net framework 4.0+ vous permettra de remplacer l'hôte dans un httpwebrequest).

La prochaine tentative sera de définir l'en-tête avec réflexion, pour contourner le problème, ce qui vous permettra de changer la valeur de l'en-tête. Mais lors de l'exécution, il écrasera cette valeur avec la partie hôte de l'URL, ce qui signifie que la réflexion ne vous apportera rien. Si le nom DNS n'existe pas, ce qui est vraiment le seul cas dans lequel vous voulez le faire en premier lieu, vous ne pouvez pas le définir, car .NET ne peut pas le résoudre, et vous ne pouvez pas remplacer le résolveur DNS .NET. Mais ce que vous pouvez faire, c'est de configurer une webproxy avec exactement la même adresse IP que le serveur de destination.

Donc, si votre adresse IP du serveur est 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; 
    } 


    } 

et le tour est joué, maintenant

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

et vous récupérez la bonne page, si 28.14.88.71 est un serveur web avec virtuel hébergement basé sur le nom (basé sur http-host-header).

+0

Nice, pour .NET 2.0. Évidemment, cela ne fonctionnera pas si vous avez réellement besoin d'utiliser un serveur proxy;) Il suffit de mettre à jour vers .NET 4.5 - WebRequest et WebClient sont tous les deux obsolètes. – User1