使用HttpClient的最佳实践

Ami*_*mar 8 c# asp.net asp.net-mvc asp.net-web-api

我正在使用HttpClient向WebApi发出请求.

我写了这段代码

 public async Task<string> ExecuteGetHttp(string url, Dictionary<string, string> headers = null)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(url);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                if (headers != null)
                {
                    foreach (var header in headers)
                    {
                        client.DefaultRequestHeaders.Add(header.Key, header.Value);
                    }
                }
                var response = await client.GetAsync(url);
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsStringAsync();
            } 
        }
Run Code Online (Sandbox Code Playgroud)

现在我从我的行动中调用这个方法.

public async Task<ActionResult> Index()
        {
            try
            {
                RestWebRequest RestWebRequest = new RestWebRequest();
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("Authorization", "bearer _AxE9GWUO__8iIGS8stK1GrXuCXuz0xJ8Ba_nR1W2AhhOWy9r98e2_YquUmjFsAv1RcI94ROKEbiEjFVGmoiqmUU7qB5_Rjw1Z3FWMtzEc8BeM60WuIuF2fx_Y2FNTE_6XRhXce75MNf4-i0HbygnClzqDdrdG_B0hK6u2H7rtpBFV0BYZIUqFuJpkg4Aus85P8_Rd2KTCC5o6mHPiGxRl_yGFFTTL4_GvSuBQH39RoMqNj94A84KlE0hm99Yk-8jY6AKdxGRoEhtW_Ddow9FKWiViSuetcegzs_YWiPMN6kBFhY401ON_M_aH067ciIu6nZ7TiIkD5GHgndMvF-dYt3nAD95uLaqX6t8MS-WS2E80h7_AuaN5JZMOEOJCUi7z3zWMD2MoSwDtiB644XdmQ5DcJUXy_lli3KKaXgArJzKj85BWTAQ8xGXz3PyVo6W8swRaY5ojfnPUmUibm4A2lkRUvu7mHLGExgZ9rOsW_BbCDJq6LlYHM1BnAQ_W6LAE5P-DxMNZj7PNmEP1LKptr2RWwYt17JPRdN27OcSvZZdam6YMlBW00Dz2T2dgWqv7LvKpVhMpOtjOSdMhDzWEcf6yqr4ldVUszCQrPfjfBBtUdN_5nqcpiWlPx3JTkx438i08Ni8ph3gDQQvl3YL5psDcdwh0-QtNjEAGvBdQCwABvkbUhnIQQo_vwA68ITg07sEYgCl7Sql5IV7bD_x-yrlHyaVNtCn9C4zVr5ALIfj0YCuCyF_l1Z1MTRE7nb");
                var getCategories = await RestWebRequest.ExecuteGetHttp("http://localhost:53646/api/Job/GetAllCategories?isIncludeChild=true", headers);
            }
            catch (HttpRequestException ex)
            {
                return View();
            }
  return View();
  }
Run Code Online (Sandbox Code Playgroud)

现在据说HttpClient被设计为可以重复用于多个呼叫.

如何为多个调用使用相同的httpClient对象.

我们假设首先我正在打电话

http://localhost:53646/api/Job/GetAllCategories?isIncludeChild=true

现在在同一个控制器中,我必须使用不同的头和不同的URL调用另一个Api.

http://localhost:53646/api/Job/category/10

我应该HttpClient为所有API调用创建全局对象并使用相同的对象.

Mur*_*oft 11

在整个应用程序中仅使用一个HttpClient的挑战是,当您想要使用不同的凭据或尝试更改请求的默认标头(或传入的HttpClientHandler中的任何内容)时.在这种情况下,您将需要一组特定目的的HttpClients来重复使用,因为只使用一个会有问题.

我建议根据你想要的"类型"请求创建一个HttpClient并重新使用它们.例如,您需要的每个凭证都有一个 - 如果您有几组默认标题,则每个凭证一个.

它可能是HttpClient属性(它们不是线程安全的)之间的一些杂耍行为,并且如果变化则需要它们自己的实例:

- BaseAddress
- DefaultRequestHeaders
- MaxResponseContentBufferSize
- Timeout
Run Code Online (Sandbox Code Playgroud)

你可以传递给"VERB"方法(获取,放置,发布等).例如,使用HttpClient.PostAsync Method (String, HttpContent)您可以指定您的标题[HttpContent][3](而不必将它们放在HttpClient DefaultHeaders中).

HttpClient的所有Async方法都是线程安全的(PostAsync)等.

  • 为每个请求创建HttpRequestMessage怎么样?然后使用HttpClient的SendAsync方法。这样,您可以在请求之间指定不同的凭据,并且仍然重复使用相同的HttpClient。 (2认同)

Cod*_*ter 8

只因为你可以,并不意味着你应该.

你不,但你可以重复使用HttpClient的,例如当你想发出一个紧密循环的HTTP请求.这节省了实例化对象所花费的一小部分时间.

您的MVC控制器将针对每个请求进行实例化.因此,同时实例化HttpClient不会损害任何大量的时间.请记住,您将使用它发出HTTP请求,这将比实例化更多的时间.

如果你坚持要重用一个实例,因为你已经对它进行了基准测试并评估了HttpClient的实例化是你最大的瓶颈,那么你可以看看依赖注入并将一个实例注入到需要它的每个控制器中.

  • 不仅要考虑性能,还要考虑应用程序的稳定性和可靠性。https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/对此提供了很好的解释。 (2认同)

Rez*_*abi 5

.net core中,您可以对HttpClientFactory执行相同的操作, 如下所示:

public interface IBuyService
{
    Task<Buy> GetBuyItems();
}

public class BuyService: IBuyService
{
    private readonly HttpClient _httpClient;

    public BuyService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<Buy> GetBuyItems()
    {
        var uri = "Uri";

        var responseString = await _httpClient.GetStringAsync(uri);

        var buy = JsonConvert.DeserializeObject<Buy>(responseString);
        return buy;
    }
}
Run Code Online (Sandbox Code Playgroud)

配置服务

services.AddHttpClient<IBuyService, BuyService>(client =>
{
     client.BaseAddress = new Uri(Configuration["BaseUrl"]);
});
Run Code Online (Sandbox Code Playgroud)

文档和示例位于此处此处