ASP.NET MVC控制器中如何全局处理API响应?
API响应统一处理重构方案
完全可以重构代码实现全局统一处理API响应,避免在每个控制器方法中重复编写相似的switch逻辑。结合你已有的BearerTokenHandler类,这里提供两种实用方案:
方案一:利用BearerTokenHandler统一处理响应
BearerTokenHandler作为DelegatingHandler,可以拦截所有通过该Handler的HttpClient请求,在SendAsync方法中统一处理响应状态码,实现全局复用。
修改BearerTokenHandler代码
public class BearerTokenHandler : DelegatingHandler { private readonly IHttpContextAccessor _httpContextAccessor; public BearerTokenHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); var context = _httpContextAccessor.HttpContext; // 统一处理各类状态码 switch (response.StatusCode) { case HttpStatusCode.Unauthorized: // 直接触发重定向到权限拒绝页面 context?.Response.Redirect("/Account/AccessDenied"); break; case HttpStatusCode.BadRequest: case HttpStatusCode.NotFound: // 解析错误信息并存入HttpContext,供控制器读取 var errorMsg = await response.Content.ReadAsStringAsync(cancellationToken); context?.Items["ApiError"] = errorMsg; break; case HttpStatusCode.OK: // 成功状态留到控制器中解析业务数据 break; default: context?.Items["ApiError"] = $"API请求失败,状态码:{response.StatusCode}"; break; } return response; } }
配置DI与控制器使用
- 注册依赖到DI容器:
// Program.cs中添加 services.AddHttpContextAccessor(); services.AddHttpClient("ApiClient") .AddHttpMessageHandler<BearerTokenHandler>();
- 控制器中简化响应处理:
public class YourController : Controller { private readonly HttpClient _httpClient; public YourController(IHttpClientFactory httpClientFactory) { _httpClient = httpClientFactory.CreateClient("ApiClient"); } public async Task<IActionResult> YourAction() { var apiResponse = await _httpClient.PostAsync("api/your-endpoint", new StringContent("请求内容")); // 仅处理成功场景,其他状态码已在Handler中处理 if (apiResponse.IsSuccessStatusCode) { var data = await apiResponse.Content.ReadFromJsonAsync<YourBusinessModel>(); return View(data); } // 从HttpContext读取统一处理的错误信息 ViewData["Error"] = HttpContext.Items["ApiError"] as string ?? "未知错误"; return View(); } }
方案二:封装独立响应处理服务
如果不想在BearerTokenHandler中耦合MVC页面重定向这类业务逻辑,可以封装一个专门的响应处理服务,将状态码处理逻辑集中管理。
创建ApiResponseHandler服务
public class ApiResponseHandler { private readonly IHttpContextAccessor _httpContextAccessor; public ApiResponseHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } public async Task<IActionResult> HandleResponseAsync( HttpResponseMessage response, Func<Task<IActionResult>> successHandler) { var context = _httpContextAccessor.HttpContext; switch (response.StatusCode) { case HttpStatusCode.OK: return await successHandler(); case HttpStatusCode.Unauthorized: return RedirectToAction("AccessDenied", "Account"); case HttpStatusCode.BadRequest: case HttpStatusCode.NotFound: context?.ViewData["Error"] = await response.Content.ReadAsStringAsync(); return View(); default: context?.ViewData["Error"] = $"请求失败,状态码:{response.StatusCode}"; return View(); } } }
控制器中使用服务
public class YourController : Controller { private readonly HttpClient _httpClient; private readonly ApiResponseHandler _responseHandler; public YourController(IHttpClientFactory httpClientFactory, ApiResponseHandler responseHandler) { _httpClient = httpClientFactory.CreateClient("ApiClient"); _responseHandler = responseHandler; } public async Task<IActionResult> YourAction() { var apiResponse = await _httpClient.PostAsync("api/your-endpoint", new StringContent("请求内容")); // 调用统一处理方法,仅传入成功场景的逻辑 return await _responseHandler.HandleResponseAsync(apiResponse, async () => { var data = await apiResponse.Content.ReadFromJsonAsync<YourBusinessModel>(); return View(data); }); } }
方案对比
- 方案一:适合全局统一拦截处理,所有使用该HttpClient的请求自动生效,代码侵入性最低。
- 方案二:逻辑更贴近MVC业务,灵活性更高,适合需要针对不同控制器做细微调整的场景。
内容的提问来源于stack exchange,提问作者Gil León
相关产品推荐
相关产品推荐

