配置 HttpClientFactory 以使用来自当前请求上下文的数据

Configure HttpClientFactory to use data from the current request context

借助 ASP.NET Core 2.1 中的新 HttpClientFactory,使用基本 URL、默认 headers 等配置自定义 HTTP 客户端非常容易

但是,我还没有找到一种方法来集中配置,让我从当前请求上下文中注入 headers。例如,考虑使用 Authorization header 调用的服务,我也希望将其传递给所有底层服务。如果能够在 Startup class 中对 services.AddHttpClient() 调用中进行配置,那就太棒了,但我不知道如何获得请求那里的上下文。

有什么想法吗?

处理这个答案让我得到了多个答案。我认为第一种方法是您正在寻找的方法,第二种方法是一个不错的选择。

为了配置多个客户端,您可以使用 named clients。这些客户端被注册为临时的。使用 DI 获取有权访问请求上下文的服务。

为此我们需要 IHttpContextAccessor。在这种情况下,您不必自己注册,因为 Identity 已经为您完成了。

否则在启动中添加以下行:

services.AddHttpContextAccessor();

接下来我们可以配置命名客户端"github":

services.AddHttpClient("github", c =>
{
    // access the DI container
    var serviceProvider = services.BuildServiceProvider();
    // Find the HttpContextAccessor service
    var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
    // Get the bearer token from the request context (header)
    var bearerToken = httpContextAccessor.HttpContext.Request
                          .Headers["Authorization"]
                          .FirstOrDefault(h => h.StartsWith("bearer ", StringComparison.InvariantCultureIgnoreCase));

    // Add authorization if found
    if (bearerToken != null)
        c.DefaultRequestHeaders.Add("Authorization", bearerToken);

     // Other settings
    c.BaseAddress = new Uri("https://api.github.com/");
    c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); // Github API versioning
    c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample"); // Github requires a user-agent
});

这样调用客户端:

public class MyController : ControllerBase
{
    private readonly IHttpClientFactory _clientFactory;

    public MyController(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }

    public async Task<ActionResult> StartCall()
    {
        var client = _clientFactory.CreateClient("github");
        var response = await client.GetAsync("/repos/aspnet/docs/issues");
    }
}

另一种选择是使用类型化客户端。这是一个简短的例子。有关完整示例,请查看 link.

注册 IHttpContextAccessor:

services.AddHttpContextAccessor();

创建类型化客户端。我添加了两个选项来添加设置。一个通过请求上下文,一个通过单例 class:

public class GitHubService
{
    public HttpClient Client { get; }

    public GitHubService(HttpClient client, HttpClientSettings httpClientSettings, IHttpContextAccessor httpContextAccessor)
    {
        var bearerToken = httpContextAccessor.HttpContext.Request
                              .Headers["Authorization"]
                              .FirstOrDefault(h => h.StartsWith("bearer ", StringComparison.InvariantCultureIgnoreCase));

        // Add authorization if found
        if (bearerToken != null)
            client.DefaultRequestHeaders.Add("Authorization", bearerToken);

        // Or the value from httpClientSettings:
        client.DefaultRequestHeaders.Add("Authorization", httpClientSettings.BearerToken);

        client.BaseAddress = new Uri("https://api.github.com/");
        client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); // GitHub API versioning
        client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample"); // GitHub requires a user-agent

        Client = client;
    }
}

注册客户端:

// The typed client is registered as transient with DI.
services.AddHttpClient<GitHubService>();

请注意,下面的代码只是一个例子。由于令牌不能持久保存在客户端中,您可以改用共享的 HttpClientSettings:

services.AddSingleton<HttpClientSettings>();

HttpClientSettings 在哪里:

public class HttpClientSettings
{
    public string BearerToken { get; set; }
}

您可以这样使用客户端:

public class MyController : ControllerBase
{
    private readonly GitHubService _gitHubService;

    public MyController(GitHubService gitHubService)
    {
        _gitHubService = gitHubService;
    }

    public async Task<ActionResult> StartCall()
    {
        var response = await _gitHubService.Client.GetAsync("/repos/aspnet/docs/issues");

    }
}

从 .NET Core 3.0 开始,您可以使用 HeaderPropagation。

在 Startup.cs

中配置服务
services.AddHeaderPropagation(o =>
        {
            o.Headers.Add("Authorization");
        });
services.AddHttpClient<YourTypedHttpClient>().AddHeaderPropagation();

在Startup.cs

中配置
app.UseHeaderPropagation();

这将自动传播授权 header。您也可以将它用于其他 header。