11

我需要为发送到我们网站的网页创建一个请求,但我也需要能够设置主机标头信息。我已经尝试过使用 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();

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

4

9 回答 9

11

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

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

反射是你的朋友:)

于 2011-09-26T19:33:06.187 回答
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();
于 2008-12-11T13:18:19.670 回答
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;

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

于 2010-12-12T11:02:09.960 回答
3

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

我所做的是创建一个来自 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;

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

于 2010-02-15T08:21:36.643 回答
3

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

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm");
request.Host = "www.mywebstite.com";
WebResponse response = request.GetResponse();
于 2015-06-18T08:18:51.017 回答
0

好吧,一点点研究发现了这一点:

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

似乎MS可能会在某个时候对此做些什么。

于 2008-12-11T11:33:00.787 回答
0

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

编辑:或者像链接问题中提到的其他人一样,只需打开一个套接字并手动快速“获取”。如果您不需要修补其他东西,比如 cookie 或 HttpWebRequest 提供的任何其他细节,那么应该是不费吹灰之力。

于 2008-12-11T11:58:01.190 回答
0

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

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

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

于 2013-09-25T17:13:43.780 回答
0

死灵术。
对于那些仍在使用 .NET 2.0的人
来说,如果您知道如何操作,这实际上很容易。

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

下一次尝试将设置带有反射的标头 - 如此处最受好评的答案所示 - 绕过它,这将让您更改标头值。但是在运行时,它会用url的 host 部分覆盖这个值,这意味着反射不会给你带来任何东西,这就是为什么我明白为什么人们继续投票的原因。

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

但是您可以做的是设置一个与目标服务器具有完全相同 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 并且实际解决方案如此简单时......

于 2016-12-21T08:09:05.267 回答