.net 如何在 HttpWebRequest 中设置自定义“Host”标头?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1450937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 13:20:54  来源:igfitidea点击:

How to set custom "Host" header in HttpWebRequest?

.nethttpreflectionhttpwebrequesthost

提问by dr. evil

How can I set a custom Host header in HttpWebRequest? I know that normally this class doesn't allow you to do so but is there anyway to use reflection or something like that without actually need me to send the whole packet with TCPClient?

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

采纳答案by feroze

There is a roundabout way to do this, as described here:

有一种迂回的方法可以做到这一点,如下所述:

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

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

However, the next version of the framework (.NET Framework 4.0) will make it easier.

但是,下一版本的框架 (.NET Framework 4.0) 将使它变得更容易。

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

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

Hope this helps.

希望这可以帮助。

回答by user2225191

You can use this hack, designed for solve this problem in .Net 3.5 .

您可以使用此 hack,旨在解决 .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;
            }

        }
    }
}

回答by Stefan Steiger

Necromancing.
For those still on .NET 2.0
It is in fact quite easy, if you know how.

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

Problem is, you can't set the host header, because the framework won't let you change the value at runtime. (.net framework 4.0+ will let you override host in a httpwebrequest).

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

Next attempt will be setting the header with reflection, to get around it, which will let you change the header value. But at runtime, it will overwrite this value with the host part of the url, which means reflection will bring you nothing.

下一次尝试将使用反射设置标头,以绕过它,这将让您更改标头值。但是在运行时,它会用 url 的主机部分覆盖这个值,这意味着反射不会给你带来任何东西。

If the dns-name doesn't exist, which is quite frankly the only case in which you want to do this in the first place, you can't set it, because .NET can't resolve it, and you can't override the .NET DNS resolver.

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

But what you can do, is setting a webproxy with the exact same IP as the destination server.

但是您可以做的是设置一个与目标服务器 IP 完全相同的 webproxy。

So, if your server IP is 28.14.88.71:

因此,如果您的服务器 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;
    }


    }

and voila, now

瞧,现在

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

and you get the correct page back, if 28.14.88.71 is a webserver with virtual name-based hosting (based on http-host-header).

如果 28.14.88.71 是具有基于虚拟名称的托管(基于 http-host-header)的网络服务器,则您会返回正确的页面。

回答by Patrick

WebClient allows it.

WebClient 允许它。

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

I couldn't tell you why. The documentation clearly states that Host is a system header.

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

回答by thedrs

you can use proxy, see my answer at: Request Web Page in c# spoofing the Host

您可以使用代理,请参阅我的回答: 在 c# 欺骗主机中请求网页