From 4f3578dc9eabefd5d3483156ea3acfe92f54a662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=9B=BD=E4=BC=9F?= <366193849@qq.com> Date: Wed, 11 Aug 2021 16:29:05 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84HttpClientFactory?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastGithub.DomainResolve/DomainResolver.cs | 2 +- FastGithub.Http/HttpClient.cs | 36 +------ FastGithub.Http/HttpClientFactory.cs | 11 +- FastGithub.Http/HttpClientHandler.cs | 114 ++++++++++++--------- FastGithub.Http/RequestContext.cs | 15 +-- FastGithub/appsettings.stackoverflow.json | 6 +- 6 files changed, 82 insertions(+), 102 deletions(-) diff --git a/FastGithub.DomainResolve/DomainResolver.cs b/FastGithub.DomainResolve/DomainResolver.cs index fd4c810..2dd894f 100644 --- a/FastGithub.DomainResolve/DomainResolver.cs +++ b/FastGithub.DomainResolve/DomainResolver.cs @@ -87,7 +87,7 @@ namespace FastGithub.DomainResolve private async Task LookupCoreAsync(IPEndPoint dns, string domain, CancellationToken cancellationToken) { var dnsClient = new DnsClient(dns); - using var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(1d)); + using var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(2d)); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); var addresses = await dnsClient.Lookup(domain, RecordType.A, linkedTokenSource.Token); diff --git a/FastGithub.Http/HttpClient.cs b/FastGithub.Http/HttpClient.cs index 5a9e04a..2ff0389 100644 --- a/FastGithub.Http/HttpClient.cs +++ b/FastGithub.Http/HttpClient.cs @@ -1,9 +1,6 @@ using FastGithub.Configuration; using FastGithub.DomainResolve; -using System; using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; namespace FastGithub.Http { @@ -12,51 +9,24 @@ namespace FastGithub.Http /// public class HttpClient : HttpMessageInvoker { - private readonly DomainConfig domainConfig; - private readonly TimeSpan defaltTimeout = TimeSpan.FromMinutes(2d); - /// /// http客户端 /// /// /// public HttpClient(DomainConfig domainConfig, IDomainResolver domainResolver) - : this(domainConfig, new HttpClientHandler(domainResolver), disposeHandler: true) + : this(new HttpClientHandler(domainConfig, domainResolver), disposeHandler: true) { } /// /// http客户端 - /// - /// + /// /// /// - internal HttpClient(DomainConfig domainConfig, HttpClientHandler handler, bool disposeHandler) + internal HttpClient(HttpClientHandler handler, bool disposeHandler) : base(handler, disposeHandler) { - this.domainConfig = domainConfig; - } - - /// - /// 发送数据 - /// - /// - /// - /// - public override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - request.SetRequestContext(new RequestContext - { - Host = request.RequestUri?.Host, - IPAddress = this.domainConfig.IPAddress, - IsHttps = request.RequestUri?.Scheme == Uri.UriSchemeHttps, - TlsSniPattern = this.domainConfig.GetTlsSniPattern(), - TlsIgnoreNameMismatch = this.domainConfig.TlsIgnoreNameMismatch - }); - - using var timeoutTokenSource = new CancellationTokenSource(this.domainConfig.Timeout ?? defaltTimeout); - using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); - return base.SendAsync(request, linkedTokenSource.Token); } } } \ No newline at end of file diff --git a/FastGithub.Http/HttpClientFactory.cs b/FastGithub.Http/HttpClientFactory.cs index 60a2596..796bcbf 100644 --- a/FastGithub.Http/HttpClientFactory.cs +++ b/FastGithub.Http/HttpClientFactory.cs @@ -1,6 +1,7 @@ using FastGithub.Configuration; using FastGithub.DomainResolve; using Microsoft.Extensions.Options; +using System.Collections.Concurrent; namespace FastGithub.Http { @@ -9,7 +10,8 @@ namespace FastGithub.Http /// sealed class HttpClientFactory : IHttpClientFactory { - private HttpClientHandler httpClientHanlder; + private readonly IDomainResolver domainResolver; + private ConcurrentDictionary domainHandlers = new(); /// /// HttpClient工厂 @@ -20,8 +22,8 @@ namespace FastGithub.Http IDomainResolver domainResolver, IOptionsMonitor options) { - this.httpClientHanlder = new HttpClientHandler(domainResolver); - options.OnChange(opt => this.httpClientHanlder = new HttpClientHandler(domainResolver)); + this.domainResolver = domainResolver; + options.OnChange(opt => this.domainHandlers = new()); } /// @@ -31,7 +33,8 @@ namespace FastGithub.Http /// public HttpClient CreateHttpClient(DomainConfig domainConfig) { - return new HttpClient(domainConfig, this.httpClientHanlder, disposeHandler: false); + var httpClientHandler = this.domainHandlers.GetOrAdd(domainConfig, config => new HttpClientHandler(config, this.domainResolver)); + return new HttpClient(httpClientHandler, disposeHandler: false); } } } \ No newline at end of file diff --git a/FastGithub.Http/HttpClientHandler.cs b/FastGithub.Http/HttpClientHandler.cs index f78eb46..2d839f1 100644 --- a/FastGithub.Http/HttpClientHandler.cs +++ b/FastGithub.Http/HttpClientHandler.cs @@ -1,4 +1,5 @@ -using FastGithub.DomainResolve; +using FastGithub.Configuration; +using FastGithub.DomainResolve; using System; using System.Collections; using System.Collections.Generic; @@ -18,23 +19,74 @@ namespace FastGithub.Http /// class HttpClientHandler : DelegatingHandler { + private readonly DomainConfig domainConfig; private readonly IDomainResolver domainResolver; + private readonly TimeSpan defaltTimeout = TimeSpan.FromMinutes(2d); /// /// HttpClientHandler /// - /// - public HttpClientHandler(IDomainResolver domainResolver) + /// + /// + public HttpClientHandler(DomainConfig domainConfig, IDomainResolver domainResolver) { this.domainResolver = domainResolver; - this.InnerHandler = CreateSocketsHttpHandler(); + this.domainConfig = domainConfig; + this.InnerHandler = this.CreateSocketsHttpHandler(); } + /// + /// 替换域名为ip + /// + /// + /// + /// + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var uri = request.RequestUri; + if (uri == null) + { + throw new FastGithubException("必须指定请求的URI"); + } + + // 请求上下文信息 + var context = new RequestContext + { + Domain = uri.Host, + IsHttps = uri.Scheme == Uri.UriSchemeHttps, + TlsSniPattern = this.domainConfig.GetTlsSniPattern().WithDomain(uri.Host).WithRandom() + }; + request.SetRequestContext(context); + + // 解析ip,替换https为http + var uriBuilder = new UriBuilder(uri) + { + Scheme = Uri.UriSchemeHttp + }; + + if (uri.HostNameType == UriHostNameType.Dns) + { + if (IPAddress.TryParse(this.domainConfig.IPAddress, out var address) == false) + { + address = await this.domainResolver.ResolveAsync(context.Domain, cancellationToken); + } + uriBuilder.Host = address.ToString(); + request.Headers.Host = context.Domain; + context.TlsSniPattern = context.TlsSniPattern.WithIPAddress(address); + } + request.RequestUri = uriBuilder.Uri; + + using var timeoutTokenSource = new CancellationTokenSource(this.domainConfig.Timeout ?? defaltTimeout); + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutTokenSource.Token); + return await base.SendAsync(request, cancellationToken); + } + + /// /// 创建转发代理的httpHandler /// /// - private static SocketsHttpHandler CreateSocketsHttpHandler() + private SocketsHttpHandler CreateSocketsHttpHandler() { return new SocketsHttpHandler { @@ -68,14 +120,14 @@ namespace FastGithub.Http { if (errors == SslPolicyErrors.RemoteCertificateNameMismatch) { - if (requestContext.TlsIgnoreNameMismatch == true) + if (this.domainConfig.TlsIgnoreNameMismatch == true) { return true; } - var host = requestContext.Host; + var domain = requestContext.Domain; var dnsNames = ReadDnsNames(cert); - return dnsNames.Any(dns => IsMatch(dns, host)); + return dnsNames.Any(dns => IsMatch(dns, domain)); } return errors == SslPolicyErrors.None; @@ -119,59 +171,23 @@ namespace FastGithub.Http /// 比较域名 /// /// - /// + /// /// - private static bool IsMatch(string dnsName, string? host) + private static bool IsMatch(string dnsName, string? domain) { - if (host == null) + if (domain == null) { return false; } - if (dnsName == host) + if (dnsName == domain) { return true; } if (dnsName[0] == '*') { - return host.EndsWith(dnsName[1..]); + return domain.EndsWith(dnsName[1..]); } return false; } - - /// - /// 替换域名为ip - /// - /// - /// - /// - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - var uri = request.RequestUri; - if (uri != null) - { - var uriBuilder = new UriBuilder(uri) - { - Scheme = Uri.UriSchemeHttp - }; - - var domain = uri.Host; - var context = request.GetRequestContext(); - context.TlsSniPattern = context.TlsSniPattern.WithDomain(domain).WithRandom(); - - if (uri.HostNameType == UriHostNameType.Dns) - { - if (IPAddress.TryParse(context.IPAddress, out var address) == false) - { - address = await this.domainResolver.ResolveAsync(domain, cancellationToken); - } - uriBuilder.Host = address.ToString(); - request.Headers.Host = domain; - context.TlsSniPattern = context.TlsSniPattern.WithIPAddress(address); - } - - request.RequestUri = uriBuilder.Uri; - } - return await base.SendAsync(request, cancellationToken); - } } } diff --git a/FastGithub.Http/RequestContext.cs b/FastGithub.Http/RequestContext.cs index 0616762..04da5f7 100644 --- a/FastGithub.Http/RequestContext.cs +++ b/FastGithub.Http/RequestContext.cs @@ -1,5 +1,4 @@ using FastGithub.Configuration; -using System.Net; namespace FastGithub.Http { @@ -14,23 +13,13 @@ namespace FastGithub.Http public bool IsHttps { get; set; } /// - /// 请求的主机 + /// 请求的域名 /// - public string? Host { get; set; } - - /// - /// 请求的ip - /// - public string? IPAddress { get; set; } + public string? Domain { get; set; } /// /// 获取或设置Sni值的表达式 /// public TlsSniPattern TlsSniPattern { get; set; } - - /// - /// 是否忽略服务器证书域名不匹配 - /// - public bool TlsIgnoreNameMismatch { get; set; } } } diff --git a/FastGithub/appsettings.stackoverflow.json b/FastGithub/appsettings.stackoverflow.json index 990bf2f..eb43648 100644 --- a/FastGithub/appsettings.stackoverflow.json +++ b/FastGithub/appsettings.stackoverflow.json @@ -2,10 +2,12 @@ "FastGithub": { "DomainConfigs": { "i.imgur.com": { - "IPAddress": "146.75.8.193" + "IPAddress": "146.75.8.193", + "TlsIgnoreNameMismatch": true }, "i.*.imgur.com": { - "IPAddress": "146.75.8.193" + "IPAddress": "146.75.8.193", + "TlsIgnoreNameMismatch": true }, "lh*.googleusercontent.com": { "Response": {