客户端多重 api 响应处理
Client-side multiple api responses handling
我的 api 有一个 returns 多种响应类型的方法:GetTokenResponse、ErrorsResponse、错误响应.
[HttpPost("token")]
[ProducesResponseType(typeof(GetTokenResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorsResponse), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), (int)HttpStatusCode.Forbidden)]
public async Task<IActionResult> GetToken([FromBody] GetTokenRequest request)
{
try
{
var token = await _authService.LoginAsync(request.Email, request.Password);
return Ok(new GetTokenResponse { Token = token });
}
catch (Exception ex) when (ex is UserNotFoundException || ex is InvalidPasswordException)
{
return BadRequest(new ErrorsResponse("Invalid username or password."));
}
catch (EmailNotConfirmedException ex)
{
return StatusCode((int)HttpStatusCode.Forbidden, new ErrorResponse(ex.Message));
}
}
并且客户端服务有一个方法来发出请求
public async Task<bool> LoginAsync(GetTokenRequest request)
{
var response = await _client.PostAsJsonAsync($"{_apiUrl}{Requests.Token}", request);
if (response.StatusCode != HttpStatusCode.OK)
{
return false;
}
var responseString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<GetTokenResponse>(responseString);
await Authenticate(result.Token, request.Email);
return true;
}
在当前的实现方法中可以 return true 或 false,仅处理 GetTokenResponse 但我想处理所有响应类型。其实就是这个问题。最好的方法是什么?
我考虑过 return 从服务中获取响应内容并在调用方解析响应类型,为响应创建基本响应类型 \ 包装器,但最佳实践是怎么说的?
我添加了抛出异常的扩展方法 EnsureSuccess()
public async Task LoginAsync(GetTokenRequest request)
{
var response = await _client.PostAsJsonAsync($"{_apiUrl}{Requests.Token}", request);
var result = await response.EnsureSuccess<GetTokenResponse>();
await Authenticate(result.Token, request.Email);
}
然后在页面上
public async Task ExecuteLogin()
{
try
{
await AuthService.LoginAsync(_request);
NavigationManager.NavigateTo("/");
}
catch (BadRequestException ex)
{
var response = ex.Response.Deserialize<ErrorsResponse>();
Errors = response.Result.Messages;
}
catch (ForbiddenException ex)
{
var response = ex.Response.Deserialize<ErrorResponse>();
Errors = new List<string> { response.Result.Message };
}
}
我的 api 有一个 returns 多种响应类型的方法:GetTokenResponse、ErrorsResponse、错误响应.
[HttpPost("token")]
[ProducesResponseType(typeof(GetTokenResponse), (int)HttpStatusCode.OK)]
[ProducesResponseType(typeof(ErrorsResponse), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ErrorResponse), (int)HttpStatusCode.Forbidden)]
public async Task<IActionResult> GetToken([FromBody] GetTokenRequest request)
{
try
{
var token = await _authService.LoginAsync(request.Email, request.Password);
return Ok(new GetTokenResponse { Token = token });
}
catch (Exception ex) when (ex is UserNotFoundException || ex is InvalidPasswordException)
{
return BadRequest(new ErrorsResponse("Invalid username or password."));
}
catch (EmailNotConfirmedException ex)
{
return StatusCode((int)HttpStatusCode.Forbidden, new ErrorResponse(ex.Message));
}
}
并且客户端服务有一个方法来发出请求
public async Task<bool> LoginAsync(GetTokenRequest request)
{
var response = await _client.PostAsJsonAsync($"{_apiUrl}{Requests.Token}", request);
if (response.StatusCode != HttpStatusCode.OK)
{
return false;
}
var responseString = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<GetTokenResponse>(responseString);
await Authenticate(result.Token, request.Email);
return true;
}
在当前的实现方法中可以 return true 或 false,仅处理 GetTokenResponse 但我想处理所有响应类型。其实就是这个问题。最好的方法是什么? 我考虑过 return 从服务中获取响应内容并在调用方解析响应类型,为响应创建基本响应类型 \ 包装器,但最佳实践是怎么说的?
我添加了抛出异常的扩展方法 EnsureSuccess()
public async Task LoginAsync(GetTokenRequest request)
{
var response = await _client.PostAsJsonAsync($"{_apiUrl}{Requests.Token}", request);
var result = await response.EnsureSuccess<GetTokenResponse>();
await Authenticate(result.Token, request.Email);
}
然后在页面上
public async Task ExecuteLogin()
{
try
{
await AuthService.LoginAsync(_request);
NavigationManager.NavigateTo("/");
}
catch (BadRequestException ex)
{
var response = ex.Response.Deserialize<ErrorsResponse>();
Errors = response.Result.Messages;
}
catch (ForbiddenException ex)
{
var response = ex.Response.Deserialize<ErrorResponse>();
Errors = new List<string> { response.Result.Message };
}
}