如果我需要每 10 分钟发出几个 http 请求,但每个请求都有自己的 cookie,那么使用 IHttpClientFactory 还是静态 HttpClient 更好?

问题描述 投票:0回答:1

我有一个业务流程(BMPN)需要进行两次http调用。第一个用于身份验证,它的主体中包含登录名和密码,其响应包含 cookie。然后我将这些 cookie 放入第二个请求中。基本上,配对的目的首先是进行身份验证,然后上传文件。但是可以有很多这样的文件要上传,每个文件都有自己的业务流程实例,因此可以同时有很多这样的实例。

我的服务目前看起来像这样:

class FileUploadService {
    private readonly string _appUrl;
    private readonly string _authServiceUrl;
    private readonly string _userName;
    private readonly string _userPassword;
    private readonly IHttpClientFactory _httpClientFactory;
    private IEnumerable<string> _cookies;

    public FileUploadService(string appUrl, string userName, string userPassword) {
        _appUrl = appUrl;
        _authServiceUrl = _appUrl + @"/ServiceModel/AuthService.svc/Login";
        _userName = userName;
        _userPassword = userPassword;

        var serviceCollection = new ServiceCollection();
        serviceCollection.AddHttpClient("MyHttpClient").ConfigurePrimaryHttpMessageHandler(
            configureHandler: () => new HttpClientHandler {
                 UseCookies = false
        });
        var serviceProvider = serviceCollection.BuildServiceProvider();
        _httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
    }

    public void TryAuthnenticate() {
        HttpClient httpClient = _httpClientFactory.CreateClient("MyHttpClient");
        string requestBody = @"{
            ""UserName"":""" + _userName + @""",
            ""UserPassword"":""" + _userPassword + @"""
            }";
        HttpContent content = new StringContent(requestBody, Encoding.UTF8, "application/json");
        HttpResponseMessage response = httpClient.PostAsync(_authServiceUrl, content).Result;
        _cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
    }

    public void TryUploadFile() {
        HttpClient httpClient = _httpClientFactory.CreateClient("MyHttpClient");
        httpClient.BaseAddress = new Uri(_appUrl);
        string filePath = @"C:\Users\defaultUser\Desktop\12345.pdf";
        string url = getUrl(filePath);
        MultipartFormDataContent content = getContent(filePath);
        HttpResponseMessage response = httpClient.PostAsync(url, content).Result;
    }

    private string getUrl(string fileInfo) {
        // some code that returns a string url
        return "";
    }

    private MultipartFormDataContent getContent(string filePath) {
        MultipartFormDataContent content = new MultipartFormDataContent();

        byte[] fileBytes = File.ReadAllBytes(filePath);
        ByteArrayContent fileContent = new ByteArrayContent(fileBytes);
        FileInfo fileInfo = new FileInfo(filePath);
        content.Add(fileContent, "12345", fileInfo.Name);
        long length = fileInfo.Length;
        long rangeEnd = length - 1;
        content.Headers.Add("Content-Range", $"bytes 0-{rangeEnd}/{length}");

        string cookieValue = "";
        foreach (var cookie in _cookies) {
           var firstCookieParts = cookie.Split(';');
           var secondCookieParts = firstCookieParts[0].Split('=');
           cookieValue = cookieValue+$"{secondCookieParts[0]}={secondCookieParts[1]}; ";
        }
        content.Headers.Add("Cookie", cookieValue);
        return content;
    }
}

我的想法是我的业务流程的每个实例都将像这样使用此服务:

FileUploadService fileUploadService = new FileUploadService("https://myhost.com", "admin", "test");
fileUploadService.TryAuthnenticate();
fileUploadService.TryUploadFile();

代码确实有效,这意味着文件已上传,但我不确定它是否会随着时间的推移而中断。有几件事我特别担心。

  1. 我的理解是,由于我需要很多HttpClient并且它们不需要很长时间,所以最好使用IHttpClientFactory。由于 CookieContainer 可以在池之间共享,因此我想摆脱 CookieContainer 并将 cookie 作为标头发送,因此

    UseCookies = false
    。但是,如果我使用一个带有
    UseCookies = false
    的静态 HttpClient 并且 cookie 将作为标头发送,会是相同/更好/更差吗?

  2. 我实例化IHttpClientFactory的方式正确吗?我能找到的 95% 的信息都是关于 ASP.NET Core 的,但我使用 .NET Core,而且我不被允许将其转换为 ASP.NET Core。所以,我不太了解我这样做的方式是否正确。

  3. IHttpClientFactory 应该是静态的吗?由于将有多个服务实例,因此将有多个 IHttpClientFactory 实例,这感觉不对,但我还没有看到使用静态 IHttpClientFactory 的示例,所以我不确定这是否有什么问题.

  4. 添加命名客户端时,我的想法是我需要以某种方式使所有 Http 客户端不使用 CookieContainer,所以我制作了这个 MyHttpClient 客户端。我不明白的是,每次我调用 CreateClient("MyHttpClient") 时,它都会是同一个 HttpClient 实例吗?它会打破拥有多个客户的整个想法吗?如果是这样,我如何让工厂只向我提供 UseCookies 设置为 false 的客户端?

该服务似乎正在工作,但我不确定我是否了解如何使用 HttpClient 和 IHttpClientFactory。我希望这个东西不会耗尽可用的套接字。

c# .net-core dotnet-httpclient httpclientfactory
1个回答
0
投票
  1. 好吧,如果您没有对命名的 HttpClient 进行许多自定义配置,并且需要在不同的类中使用这些配置,那么就没有必要使用

    IHttpClientFactory
    ..如果您只有 1 个配置,并且希望使用该服务的所有实例如果客户端具有相同的配置,那么您可以在类中创建 HttpClient 并在那里进行配置。看看这个 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-8.0#named-clientsIHttpClientFactory

  2. 这取决于一个人认为什么是正确的。我想说最好在单独的类中进行服务绑定,在该类中进行 DI 操作,并且您的

    FileUploadService
    构造函数应该具有
    IHttpClientFactory clientFactory
    参数。然后,当从 DI 容器请求
    FileUploadService
    时,您配置的 DependencyResolver 将尝试获取实现 IHttpClientFactory 的类的实例,并将其传递给
    FileUploadService
    的构造函数。

  3. 就你而言,我认为工厂是否静态并不重要,即使你有超过 1 个

    FileUploadService
    实例。因为您仅使用工厂中的
    CreateClient
    方法,该方法实际上创建并返回
    HttpClient
    的新实例。所以你总是会得到一个新的客户端实例。这里更合适的问题是 你应该使用 1 个
    HttpClient
    实例吗?
    关于你可以在这里找到一些有用的信息: https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

    在 WebAPI 客户端中每次调用创建新的 HttpClient 的开销是多少?

  4. 嗯,您实际上可以轻松检查这一点,在调试时只需多次调用它,并在您创建的客户端上使用

    Object.ReferenceEquals()
    。最后,如果您决定使用 1 个 HttpClient 实例,那么我看不出使用工厂的目的。

© www.soinside.com 2019 - 2024. All rights reserved.