我有一个 API 中间层,用于捕获请求、生成令牌,然后将该请求传递到预期的 API 端点。一次只能创建一个令牌,因此每个请求都需要检查是否存在有效令牌并使用它,或者创建一个新令牌。如果中间层API同时收到多个请求,它仍然应该只创建一个token。
为此,我使用 SemaphoreSlim:
接受请求以检查某些内容的当前版本的控制器:
[ApiController]
[Route("[controller]")]
[AuthorizationKey]
public class Controller : ControllerBase
{
private readonly ILogger<Controller> Logger;
private readonly Services Services;
public Controller(ILogger<Controller> logger, Services services)
{
Logger = logger;
Services = services;
}
[HttpGet]
[Route("version")]
[ResponseCache(NoStore = true, Duration = 0, Location = ResponseCacheLocation.None)]
public async Task<ActionResult> Version()
{
try
{
var result = await Services.GetVersionAsync();
var response = result.Content.ReadAsStringAsync();
if (result.StatusCode == HttpStatusCode.OK)
{
return Ok(response.Result);
}
else if (result.StatusCode == HttpStatusCode.Unauthorized)
{
return StatusCode(401, response.Result);
}
else
{
return StatusCode(500, response.Result);
}
}
catch (Exception ex)
{
return StatusCode(500);
}
}
}
这是我服务的课程:
public class Services
{
private readonly ILogger<Services> Logger;
private readonly IConfiguration Configuration;
private readonly IHttpClientFactory HttpClientFactory;
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public Services(ILogger<Services> logger, IConfiguration configuration, IHttpClientFactory httpClientFactory)
{
Logger = logger;
Configuration = configuration;
HttpClientFactory = httpClientFactory;
}
public async Task<HttpResponseMessage> GetVersionAsync()
{
var httpClient = await CreateHttpClient();
var response = await httpClient.GetAsync(Configuration["VERSION_ENDPOINT"]);
return response;
}
#region Helpers
private async Task<HttpClient> CreateHttpClient()
{
var token = await GetAccessTokenAsync();
var httpClient = HttpClientFactory.CreateClient();
httpClient.BaseAddress = new Uri(Configuration["API_URI"]);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return httpClient;
}
private async Task<string> GetAccessTokenAsync()
{
await _semaphore.WaitAsync();
try
{
//Checks for a token in a table and returns it if it is valid, or gets a new one if one does not exist
/if no token, then it calls RequestAccessTokenAsync()
}
finally
{
_semaphore.Release();
}
}
private async Task<TokenResponse> RequestAccessTokenAsync()
{
//Gets a new token from a service
}
#endregion
}
如果我同时提交多个请求,则会创建多个令牌。我提交的请求数量并不总是一对一的。例如,我做了 2 个请求,它创建了 2 个令牌,3 个请求,它创建了 2 个令牌,现在我只做了 10 个请求,它创建了 7 个令牌,但无论哪种方式,我只想一次创建 1 个有效令牌。
将以下代码切换到静态解决了该问题。再次感谢用户“Deleted”的帮助。
private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);