如何在ASP.NET Core控制器式Web API中处理Supabase Postgrest异常?
处理Supabase Postgrest异常的解决方案
当传入非UUID格式的字符串调用接口时,Supabase的Postgrest客户端会抛出PostgrestException(错误码22P02),当前代码未捕获该异常,导致API返回500内部服务器错误,不符合REST规范。以下是几种可行的处理方式:
方式一:控制器内直接捕获异常
在DatabasesController.cs的GetById方法中添加try-catch块,针对特定错误码返回对应HTTP响应:
using Project.Services; using Project.Models; using Microsoft.AspNetCore.Mvc; using Supabase.Postgrest.Exceptions; namespace Project.Controllers; [ApiController] [Route("[controller]")] public class DatabasesController : ControllerBase { private readonly DatabasesService _databasesService; public DatabasesController(DatabasesService databasesService) => _databasesService = databasesService; [HttpGet] public async Task<List<Database>> GetAll() => await _databasesService.GetAll(); [HttpGet("{id}")] public async Task<ActionResult<Database>> GetById(string id) { try { var response = await _databasesService.GetById(id); var database = response.FirstOrDefault(); return database is not null ? database : NotFound(); } catch (PostgrestException ex) { if (ex.Code == "22P02") { return BadRequest(new { Message = "无效的UUID格式,请提供正确的UUID字符串" }); } return StatusCode(StatusCodes.Status500InternalServerError, new { Message = "服务器内部错误", Details = ex.Message }); } } }
方式二:服务层封装结果(解耦控制器与异常处理)
先定义通用结果类(可放在Models目录下):
namespace Project.Models; public class ServiceResult<T> { public T? Data { get; set; } public string? ErrorMessage { get; set; } public string? ErrorCode { get; set; } public bool IsSuccess => string.IsNullOrEmpty(ErrorMessage); }
修改DatabasesService.cs的GetById方法,返回封装后的结果:
using Project.Models; using Supabase; using Supabase.Postgrest.Exceptions; namespace Project.Services; public class DatabasesService { private readonly Client _supabaseClient; public DatabasesService(Client supabaseClient) { _supabaseClient = supabaseClient; } public async Task<List<Database>> GetAll() { var result = await _supabaseClient.From<Database>().Get(); return result.Models; } public async Task<ServiceResult<List<Database>>> GetById(string id) { try { var result = await _supabaseClient .From<Database>() .Where(x => x.Id == id) .Get(); return new ServiceResult<List<Database>> { Data = result.Models }; } catch (PostgrestException ex) { return new ServiceResult<List<Database>> { ErrorMessage = ex.Message, ErrorCode = ex.Code }; } } }
再修改控制器逻辑,根据结果返回响应:
[HttpGet("{id}")] public async Task<ActionResult<Database>> GetById(string id) { var result = await _databasesService.GetById(id); if (!result.IsSuccess) { if (result.ErrorCode == "22P02") { return BadRequest(new { Message = "无效的UUID格式,请提供正确的UUID字符串" }); } return StatusCode(StatusCodes.Status500InternalServerError, new { Message = result.ErrorMessage }); } var database = result.Data?.FirstOrDefault(); return database is not null ? database : NotFound(); }
方式三:全局异常过滤器(推荐多接口场景)
创建全局异常过滤器类(可放在Filters目录下):
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Supabase.Postgrest.Exceptions; namespace Project.Filters; public class PostgrestExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { if (context.Exception is PostgrestException ex) { ObjectResult result; switch (ex.Code) { case "22P02": result = new BadRequestObjectResult(new { Message = "无效的UUID格式,请提供正确的UUID字符串" }); break; case "404": result = new NotFoundObjectResult(new { Message = "请求的资源不存在" }); break; default: result = new ObjectResult(new { Message = "服务器内部错误", Details = ex.Message }) { StatusCode = StatusCodes.Status500InternalServerError }; break; } context.Result = result; context.ExceptionHandled = true; } } }
在Program.cs中注册过滤器:
var builder = WebApplication.CreateBuilder(args); // ... 其他服务注册代码 ... builder.Services.AddControllers(options => { options.Filters.Add<PostgrestExceptionFilter>(); // 添加全局异常过滤器 }).AddNewtonsoftJson(); // ... 其他代码 ...
额外优化:提前验证输入格式
在控制器参数上添加正则验证,提前拦截无效UUID,避免走到数据库查询步骤:
[HttpGet("{id}")] public async Task<ActionResult<Database>> GetById( [RegularExpression(@"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", ErrorMessage = "无效的UUID格式")] string id) { // ... 方法内容 ... }
内容的提问来源于stack exchange,提问作者not-a
相关产品推荐
相关产品推荐

