Запрос веб-страницы в c # подмене хоста - PullRequest
11 голосов
/ 11 декабря 2008

Мне нужно создать запрос на веб-страницу, доставляемую на наши веб-сайты, но мне также нужно иметь возможность установить информацию заголовка узла. Я пробовал это с помощью HttpWebRequest, но информация заголовка только для чтения (или, по крайней мере, часть Host это). Мне нужно сделать это, потому что мы хотим выполнить начальный запрос страницы, прежде чем пользователь сможет. У нас есть 10 веб-серверов с балансировкой нагрузки, поэтому нам нужно запросить файл с каждого из веб-серверов.

Я пробовал следующее:

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

Очевидно, это не работает, так как я не могу обновить заголовок, и я не знаю, действительно ли это правильный способ сделать это.

Ответы [ 9 ]

10 голосов
/ 26 сентября 2011

Хотя это очень запоздалый ответ, возможно, кто-то может получить от него пользу

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

Отражение твой друг:)

9 голосов
/ 11 декабря 2008

Мне удалось найти более длинный маршрут, используя сокеты. Я нашел ответ на странице MSDN для IPEndPoint:

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();
4 голосов
/ 12 декабря 2010

У меня была проблема, когда использованный 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)

2 голосов
/ 15 февраля 2010

Я знаю, что это старо, но я столкнулся с той же самой проблемой, и я нашел лучшее решение, чем использование сокетов или отражения ...

Что я сделал, так это создал новый класс, который работает с WebHeaderCollection и обходит проверку того, что вы вставляете в него:

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;

Надеюсь, это поможет любому, кто ищет это!

1 голос
/ 18 июня 2015

Я знаю, что это старый вопрос, но в наши дни вы можете это сделать.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm");
request.Host = "www.mywebstite.com";
WebResponse response = request.GetResponse();
0 голосов
/ 21 декабря 2016

Necromancing.
Для тех, кто все еще на .NET 2.0
Это на самом деле довольно легко, если вы знаете, как.

Проблема в том, что вы не можете установить заголовок хоста, потому что среда не позволит вам изменить значение во время выполнения. (.net Framework 4.0+ позволит вам переопределить хост в httpwebrequest).

Следующая попытка будет установить заголовок с отражением - как показано в ответе с верхним голосом здесь - чтобы обойти его, что позволит вам изменить значение заголовка. Но во время выполнения он перезапишет это значение с хост-частью URL , что означает, что рефлексия вам ничего не принесет, поэтому я не понять, почему люди продолжают голосовать за это.

Если dns-name не существует, что, честно говоря, является единственным случаем, когда вы хотите сделать это в первую очередь, вы не можете установить его, потому что .NET не может его разрешить, и вы не может переопределить .NET DNS resolver.

Но вы можете настроить веб-прокси с тем же 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).

Теперь у вас есть правильный ответ на исходный вопрос как для WebRequest, так и для WebClient. Я думаю, что использование пользовательских сокетов для этого было бы неправильным подходом, особенно когда нужно использовать SSL и когда такое простое реальное решение ...

0 голосов
/ 25 сентября 2013

Вы можете использовать мое решение для этой проблемы, оно размещено здесь:

Как установить собственный заголовок "Host" в HttpWebRequest?

Это может помочь вам отредактировать заголовок хоста и избежать использования прокси и прямых запросов сокетов.

0 голосов
/ 11 декабря 2008

Заголовок «Хост» защищен и не может быть изменен программно. Я полагаю, что для обхода этой проблемы вы можете попытаться выполнить привязку через отражение к частному свойству InnerCollection объекта WebRequest и вызвав для него метод «Set» ar «Add», чтобы изменить заголовок Host. Я не пробовал этого, но после быстрого просмотра исходного кода в Reflector, я думаю, что это легко сделать. Но да, привязка к частным свойствам каркасных объектов не лучший способ для достижения цели. :) Используйте только если вы ДОЛЖНЫ.

edit: Или, как другой парень упоминает в связанном вопросе, просто откройте сокет и выполните быстрый «GET» вручную. Это должно быть понятно, если вам не нужно возиться с другими вещами, такими как куки или что-то еще, что предоставляет HttpWebRequest.

0 голосов
/ 11 декабря 2008

Хорошо, небольшое исследование обнаруживает это:

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

Кажется, MS может что-то сделать с этим в какой-то момент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...