【问题标题】:Setting Accept Header without using MediaTypeWithQualityHeaderValue在不使用 MediaTypeWithQualityHeaderValue 的情况下设置 Accept Header
【发布时间】:2015-08-19 09:21:18
【问题描述】:

在 Asp.Net Web Api 2 中,使用以下传统方法设置 HttpClient Accept Header 有什么区别:

        HttpClient client = HttpClientFactory.Create(handler);

        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

还有以下方法:

var headers = new Dictionary<string, string>
            {
                {"Accept", "application/json"}};

headers.ForEach(h => client.DefaultRequestHeaders.Add(h.Key, h.Value));

更新 1:

根据@DarrenMiller 在以下帖子What is the overhead of creating a new HttpClient per call in a WebAPI client? 中的回答,似乎首选方法是使用DefaultRequestHeaders 属性,因为它包含用于多次调用的属性。这是否意味着如果我使用简单的字典设置默认标题,我的HttpClient client 将不如使用DefaultRequestHeaders 的效率高?另外我真的不明白DefaultRequestHeaders 中的值将如何被重用?假设我使用 HttpClientFactory.Create 创建了 20 个 HttpClient client,并在其中的每一个中设置了 DefaultRequestHeaders 属性 [我真的需要这样做,因为 DefaultRequestHeaders 是为了被重用吗?!]。每次创建HttpClient client 时设置DefaultRequestHeaders 是否会导致某种性能下降?

【问题讨论】:

  • 可能是因为您正在向Accept 添加内容,而在第二种情况下您正在向其他地方添加内容。
  • 最好的办法是使用 Fiddler (telerik.com/fiddler) 之类的东西来观察在 Fiddler 运行时执行这两种方法时请求中实际发送的内容。它将记录 HTTP 流量并允许您查看差异。
  • @MHOOS RE 您的更新:您应该重复使用您的HttpClient。只有这样,默认标头才会被重用。

标签: c# web-services asp.net-web-api asp.net-web-api2


【解决方案1】:

您的问题之一:添加标题有什么不同吗?

HttpClient client = HttpClientFactory.Create(handler);

方法一:

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

方法二:

var headers = new Dictionary<string, string>{{"Accept", "application/json"}};
headers.ForEach(h => client.DefaultRequestHeaders.Add(h.Key, h.Value));

方法 1 为您提供了很好的强类型值,并且能够添加多个接受类型。方法 2 多了一个“魔术字符串”,可能是拼写错误的地方,并且无法添加多个接受类型。

您问题的第 2 部分:性能和重用价值在哪里?

为每个请求使用新的 HttpClient 对性能的影响取决于您的用例。获得一个基准并衡量它是否重要。开发人员的表现最有可能获得收益。考虑到您使用的每个 HttpClient 都必须记住要添加的一堆标头。如果您忘记添加正确的标题,则会发生错误。因此,您可以使用 DefaultRequestHeaders 在工厂中进行设置。

public class ApiService
{
    public static HttpClient GetClient()
    {
        var client = new HttpClient(new Uri("https://someservice/"));
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
        //add any other setup items here.
        return client;
    }
}

现在使用它:

public async Task DoStuff()
{
    using(var client = ApiService.GetClient())
    {
        //client will have the proper base uri and all the headers set.
        var data = await client.GetAsync<dynamic>("Sales");

        //client will still have the proper base uri and all the headers set.
        var data2 = await client.GetAsync<dynamic>("Products");
    }
}

HttpClients 应该是短暂的,并且总是包含在 using 语句中。当使用同一个客户端发出多个请求时,就会发生重用。

更新

正如其他人所提到的,Microsoft 建议在应用程序的整个生命周期中保留一个 HttpClient 以避免过多的开销。获取 HttpClient 的首选方法是声明一个静态的,然后根据需要引用它。请注意,默认标头中设置的任何内容都会随每个请求一起消失,因此请确保不要将诸如授权之类的内容放在那里,除非您确定请求的最终目的地。

【讨论】:

  • “HttpClients 应该是短暂的”——还有其他与此相矛盾的指南(例如:stackoverflow.com/a/22561368/306430)。重建 HttpClient(并重新建立底层连接)可能会很昂贵,因此人们也可以长期重用 HttpClient 用于对性能和/或可扩展性敏感的站点。
  • 我猜“短命”是主观的。从来没有一个包罗万象的解决方案。正如我上面提到的,个别用例将决定最佳解决方案。通过 for 循环运行它,可能不是一个好主意。在整个使用本机应用程序的过程中保持单个 HttpClient 活动数小时,这可能不是一个好主意。总会有妥协的地方。感谢您的反馈。
  • 永远不要将 HttpClient 包含在 using 语句中(可能有一些罕见的例外)。始终尽可能重用 HttpClient 以防止套接字耗尽,请参阅 this post 了解有关连接生命周期问题的更多信息。
  • @Aldracor,你是对的,你不应该将 HttpClient 包装在 using 中。这现在广为人知,但 5 年前当我回答这个问题时,它并不为人所知。此外,这取决于您的应用程序的结构。如果这是一个 Azure 函数,包装它会非常好,因为这是一个运行一次的场景。绝不是一个苛刻的词;)
  • 我在答案中添加了一个更新,以反映在应用程序的整个生命周期中首选单个 HttpClient。
猜你喜欢
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-05
  • 2012-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多