【问题标题】:C# HttpClient refresh token strategyC# HttpClient 刷新令牌策略
【发布时间】:2018-04-21 07:48:37
【问题描述】:

由于 Microsoft recommends HttpClient 被创建一次并在程序的整个生命周期中重复使用,我想知道如何更新 DefaultRequestHeaders,例如,令牌已过期并需要刷新。

DefaultRequestHeaders 不是线程安全的(据我所知),并且在那里定义的标头列表由所有潜在的待处理请求共享。 Clear() 列表和 Add() 带有新令牌的标头,似乎不是明智的做法。


更新

更准确地说,我不想/不需要为每个请求更改请求标头。仅当我获得 HTTP 401 状态代码时。

【问题讨论】:

  • 不要使用辅助方法,构建一个HttpRequestMessage 并改用SendAsync
  • 想一想,你可能会写一个 HttpClientHandler ,它会根据请求的去向自动添加标头。
  • @john 使用SendAsyncHttpClientHandler 将无助于更改标头,例如在令牌过期后授权失败时。除了@brennan-mann 指出的DelegatingHandler 似乎更合适
  • 在下面的代码示例中,有一个查看响应的消息处理程序。您可以查看 HttpStatus 并检查 401 响应,更新您的令牌并重新提交。您的令牌是否具有到期或生存时间,您可以在发送请求之前检查这些属性吗?
  • @PhilippeLécaillon 我不是在谈论更改标题,我是在谈论完全远离DefaultRequestHeaders。我看到布伦南同意了我的第二个想法:)

标签: c# httpclient delegatinghandler


【解决方案1】:

当您在 DI 容器注册阶段注册 IHttpClient 或使用其他模式(例如工厂或单例)返回带有自定义消息处理程序的 IHttpClient 实例时,将消息处理程序与您的 HttpClient 连接起来。检查出站呼叫并添加必要的标头。

https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/httpclient-message-handlers

示例标头消息处理程序

class MessageHandler1 : DelegatingHandler
    {


    private int _count = 0;

    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        System.Threading.Interlocked.Increment(ref _count);
        request.Headers.Add("X-Custom-Header", _count.ToString());
        return base.SendAsync(request, cancellationToken);
    }
}

示例记录器消息处理程序:

class LoggingHandler : DelegatingHandler

{
    StreamWriter _writer;

public LoggingHandler(Stream stream)
{
    _writer = new StreamWriter(stream);
}

protected override async Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
    var response = await base.SendAsync(request, cancellationToken);

    if (!response.IsSuccessStatusCode)
    {
        _writer.WriteLine("{0}\t{1}\t{2}", request.RequestUri, 
            (int)response.StatusCode, response.Headers.Date);
    }
    return response;
}

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        _writer.Dispose();
    }
    base.Dispose(disposing);
}

}

将其添加到管道中

HttpClient client = HttpClientFactory.Create(new Handler1(), new Handler2(), new Handler3());

线程问题

关于线程问题或并发,HttpRequestMessage 方法上的 HttpRequestMessage 参数将针对每个请求。如果您将标头添加到 request.Headers 集合,您将仅更新该请求实例的标头(即,不是全局的)

或者在request.Headers 实例上使用 Authorization 属性:

request.Headers.Authorization = new AuthenticationHeaderValue("bearer", bearerToken);

请参阅下面的 MSDN 链接

https://msdn.microsoft.com/en-us/library/system.net.http.httprequestmessage

如果您在 HttpClient 的静态、共享、单例、Lifestyle.Singleton 等实例上使用 DefaultRequestHeaders,那么您将遇到线程问题并且需要适当的同步来更新 DefaultRequestHeaders 集合。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-01
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多