在C#的HttpClient中是否可以设置自定义DNS解析器?

8

what exactly I want :

public static CustomDnsResolver : Dns 
{
   .....
}

public static void Main(string[] args) 
{
    var httpClient = new HttpClient();
    httpClient.Dns(new CustomDnsResolver());
}

基本上,我只想在 HttpClient 中使用自定义 DNS 解析器而不是系统默认解析器,有什么办法可以实现吗?

3个回答

5
您所需的用例正是微软构建HttpClient堆栈的原因。它允许您使用HttpMessageHandler类将业务逻辑放入分层类中。您可以在ms docsvisualstudiomagazine中找到一些示例。请注意,保留HTML标记。
void Main()
{
    var dnsHandler = new DnsHandler(new CustomDnsResolver());
    var client = new HttpClient(dnsHandler);
    var html = client.GetStringAsync("http://google.com").Result;
}

public class DnsHandler : HttpClientHandler
{
    private readonly CustomDnsResolver _dnsResolver;

    public DnsHandler(CustomDnsResolver dnsResolver)
    {
        _dnsResolver = dnsResolver;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var host = request.RequestUri.Host;
        var ip = _dnsResolver.Resolve(host);

        var builder = new UriBuilder(request.RequestUri);
        builder.Host = ip;

        request.RequestUri = builder.Uri;

        return base.SendAsync(request, cancellationToken);
    }
}

public class CustomDnsResolver
{
    public string Resolve(string host)
    {
        return "127.0.0.1";
    }
}

4
如果你尝试从一个https网站获取数据,这个解决方案就不起作用了。 - Mohammad Nikravan
您可以覆盖证书验证以解决此问题。 - Kalten
你可以重写 HttpClientHandler 的 ServerCertificateCustomValidationCallback 方法来自定义证书验证。 - Dylech30th
2
这并没有回答问题。你不能只是说:“覆盖证书验证”,期望的是我们正确设置主机名,使SSL正常工作,但避免DNS查找。 - Luke Briner
这个答案适用于一组限制条件。我不建议您使用通用答案。如果它能够帮助到某些人,我仍然很高兴。如果有人能提出更好的答案,我会感激他的。 - Kalten
实际上,我们可以通过其他方式绕过证书验证。但是我们遇到了另一个问题,当服务器端仅接受来自主机名而非IP的请求时,这个解决方案就会失败。 :-( - Leo Li

4

不确定是否适用于所有情况,但是对于我的情况,即使使用HTTPS也非常有效。所以你需要将URL中的主机名替换为自定义解析器已经解析出来的实际IP地址,然后只需添加一个"host"头部信息,并在其中写上主机名即可。像这样:

        var requestUri = new Uri("https://123.123.123.123/some/path");
        using var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
        request.Headers.TryAddWithoutValidation("host", "www.host-name.com");
        using var response = await httpClient.SendAsync(request);

我希望这可以帮到你,因为这不是我第一次遇到这个问题,但以前从未能解决过。

如果您还按照Dylech30th在另一个答案中提到的评论覆盖证书错误,那么这仅适用于https。 - Ross Presser
嗯...我实际上今天在生产中使用它,而且它的效果非常好。我没有以任何方式覆盖证书错误。我使用SocketsHttpHandler并在.NET 6中运行。这怎么可能呢? - Hans Olav
3
我已经对SocketsHttpHandler的行为变化进行了一些挖掘,正如您在https://github.com/dotnet/runtime/issues/45144中所看到的那样,实际原因是服务器需要进行SNI验证。在.NET 5之前,主机标头不会自动用作SNI,但是这种行为在.NET 5中发生了变化,如果设置了主机标头,则现在强制使用主机标头作为SNI。 - Dylech30th


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接