使用httpClient.GetAsync时添加头信息

282

我正在使用Apiary.io实现同事们制作的API,应用于Windows Store应用项目。

他们展示了一个我需要实现的方法的示例:

var baseAddress = new Uri("https://private-a8014-xxxxxx.apiary-mock.com/");

using (var httpClient = new HttpClient{ BaseAddress = baseAddress })
{
    using (var response = await httpClient.GetAsync("user/list{?organizationId}"))
    {
        string responseData = await response.Content.ReadAsStringAsync();
    }
}
在这种方法和其他一些方法中,我需要具有一个在之前获取的令牌的标题。 这是Postman(Chrome扩展程序)带有我所说的标题的图像: enter image description here 如何将Authorization标题添加到请求中?

12
警告 针对可能的代码搜索者:这是一个错误使用 HttpClient 的例子!请查看 https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ 了解详情。 - 321X
6个回答

527

虽然这是一个较晚的答案,但因为没有人提供这个解决方案...

如果您不想直接在HttpClient实例上设置标头,即将其添加到DefaultRequestHeaders中(以便不将其发送到您将使用它进行的所有请求),您可以针对每个请求设置标头

但是,您将被迫使用SendAsync()方法,该方法是唯一接受HttpRequestMessage实例作为输入的方法(允许配置标头)。

如果您想要重用HttpClient,这是正确的解决方案-- 这是最佳实践

像这样使用它:

using (var requestMessage =
            new HttpRequestMessage(HttpMethod.Get, "https://your.site.com"))
{
    requestMessage.Headers.Authorization =
        new AuthenticationHeaderValue("Bearer", your_token);
    
    await httpClient.SendAsync(requestMessage);
}

16
如果值经常变化,不使用DefaultRequestHeaders似乎更安全。 - Jason Rowe
3
请注意,您很可能需要使用requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", your_token);。"Bearer"将是一个无效的HTTP报头。 - Chris Marisic
2
@JCKodel,它会增加噪音,因为您不一定需要使用 using,但可以在构造函数中实例化并在 Dispose() 中处置。 - Philippe
4
我从未说过要在 HttpClient 上使用 using(这是不好的),我是说在 HttpRequesMessage 上使用(因为它有用于流式传输的非托管内存缓冲区,在使用后必须释放)。每次请求和响应都必须被处理(否则会锁定大量内存块很长一段时间)。HttpClient 可以被重复使用,但有限制。 - JCKödel
2
最好为每个API/服务器拥有一个httpClient进行查询,并尽可能长时间地保留它。这通常与使用“using”不兼容。静态可能是好的(至少比多个实例好),但更好的方法是使用依赖注入。在整个应用程序生命周期中保留一个实例是很好的。 - Philippe
显示剩余10条评论

258

使用HttpClient的GetAsync方法时,可以像下面这样添加授权标头:

httpClient.DefaultRequestHeaders.Authorization 
                         = new AuthenticationHeaderValue("Bearer", "Your Oauth token");

这样做会在 HttpClient 的生命周期内添加授权头,因此如果您只访问一个站点并且授权头不会改变,则此方法很有用。

以下是关于此问题的详细解答:SO answer


86
-1 是因为 HttpClient 必须是可重用的(参见 https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/)。如果必须是可重用的,那么设置默认请求标头是一种不好的做法。 - JCKödel
47
@JCKödel,你在做出错误的假设。如果您在HttpClient的生命周期内始终使用相同的凭据调用同一站点,则使用DefaultRequestHeaders可以避免您不断地使用相同值重新设置它们。您应该重新阅读文章,它谈到了使用HttpClient的同一实例,但并没有对默认请求标头的使用提出不良实践的说法。如果我只是在实践中使用HTTP客户端调用一个站点,则使用DefaultRequestHeaders可以避免每次都需要设置它们。 - kmcnamee
5
@JCKödel,尽管你的假设是错误的,但我点了赞,因为你提出了一个重要观点。这为回答增加了更大的清晰度。 - Najeeb
1
@kmcnamee,如果我需要传递两个令牌怎么办? - Najeeb

109

已经接受的答案虽然可行,但当您想尝试添加Accept头时可能会变得复杂。以下是我最终使用的方法,对我来说似乎更简单,因此我认为将来会坚持使用:

client.DefaultRequestHeaders.Add("Accept", "application/*+xml;version=5.1");
client.DefaultRequestHeaders.Add("Authorization", "Basic " + authstring);

但是当我再次调用API时,我遇到了错误,如“无法添加值,因为标题'Authorization'不支持多个值”。 - Akash Limbani
1
如果您正在重复使用同一客户端,请在尝试添加之前进行检查。if (!client.DefaultRequestHeaders.Contains("Authorization")) { client.DefaultRequestHeaders.Add("Authorization", "Basic " + authstring); } - Rick

18

有时候,你只需要这段代码。

 httpClient.DefaultRequestHeaders.Add("token", token);

8

根据新手的答案,你可以像这样使用“扩展”:

  public static class HttpClientExtensions
    {
        public static HttpClient AddTokenToHeader(this HttpClient cl, string token)
        {
            //int timeoutSec = 90;
            //cl.Timeout = new TimeSpan(0, 0, timeoutSec);
            string contentType = "application/json";
            cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
            cl.DefaultRequestHeaders.Add("Authorization", String.Format("Bearer {0}", token));
            var userAgent = "d-fens HttpClient";
            cl.DefaultRequestHeaders.Add("User-Agent", userAgent);
            return cl;
        }
    }

并使用:

string _tokenUpdated = "TOKEN";
HttpClient _client;
_client.AddTokenToHeader(_tokenUpdated).GetAsync("/api/values")

3

现在,如果您正在使用MS Dependency Injection,强烈建议插入IHttpClientFactory:

builder.Services.AddHttpClient("GitHub", httpClient =>
{
    httpClient.BaseAddress = new Uri("https://api.github.com/");

    // using Microsoft.Net.Http.Headers;
    // The GitHub API requires two headers.
    httpClient.DefaultRequestHeaders.Add(
        HeaderNames.Accept, "application/vnd.github.v3+json");
    httpClient.DefaultRequestHeaders.Add(
        HeaderNames.UserAgent, "HttpRequestsSample");
});

var httpClient = _httpClientFactory.CreateClient("GitHub");

这样做可以避免将默认请求标头添加到全局共享的httpclient中,而且不必处理手动创建HttpRequestMessage的问题。
来源: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-6.0#consumption-patterns

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接