基于.NET 8 Web API实现空路由参数自定义422错误响应问询
.NET 8 Web API路由参数为空时返回自定义422错误响应
问题说明
使用.NET 8默认ASP.NET Core Web API模板开发接口,路由路径结构无法修改(不能将路由参数转为查询参数)。当前接口定义了三个路由参数routeParam1、routeParam2、routeParam3,当请求中某路由参数为空(如路径中出现连续//)时,ASP.NET Core默认返回404 Not Found,需改为返回对应自定义内容的422 Unprocessable Entity响应。
解决方案
由于ASP.NET Core路由系统默认不匹配空路由参数的请求,因此需要先让请求能匹配到目标接口再校验参数;或通过中间件提前拦截请求并校验路由段。以下提供两种实现方式:
方式1:修改路由允许可选参数,在Action内直接校验
步骤1:更新路由与参数定义
将路由模板中的参数改为可选(添加?),并将路由参数类型改为可空字符串,确保空参数的请求能匹配到该Action:
[HttpGet] [Route("{routeParam1?}/{routeParam2?}/path/{routeParam3?}", Name = "XYZ")] [Produces("application/json")] public async Task<IActionResult> XYZ( [FromRoute] string? routeParam1, [FromRoute] string? routeParam2, [FromRoute] string? routeParam3, [FromQuery] string queryParam1, [FromQuery] string queryParam2, CancellationToken cancellationToken) {
步骤2:添加参数校验逻辑
在Action开头逐一校验路由参数是否为空,为空则返回对应的422响应:
// 校验routeParam1 if (string.IsNullOrWhiteSpace(routeParam1)) { return UnprocessableEntity(new { customCode = "1111", warning = "routeParam1 is required." }); } // 校验routeParam2 if (string.IsNullOrWhiteSpace(routeParam2)) { return UnprocessableEntity(new { customCode = "2222", warning = "routeParam2 is required." }); } // 校验routeParam3 if (string.IsNullOrWhiteSpace(routeParam3)) { return UnprocessableEntity(new { customCode = "3333", warning = "routeParam3 is required." }); } // 原有业务逻辑 return new ObjectResult("ok") { StatusCode = 200 };
方式2:使用中间件拦截请求并校验路由段
若不想修改Action的参数定义,可通过自定义中间件提前解析请求路径,校验对应位置的路由段是否为空:
步骤1:实现自定义中间件
public class RouteParamValidationMiddleware { private readonly RequestDelegate _next; public RouteParamValidationMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { var pathSegments = context.Request.Path.Value? .Split('/', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>(); // 匹配目标路由结构:{routeParam1}/{routeParam2}/path/{routeParam3} bool matchesTargetRoute = pathSegments.Length >= 3 && pathSegments[2].Equals("path", StringComparison.OrdinalIgnoreCase); if (matchesTargetRoute) { // 校验routeParam1(对应路径第1段) if (pathSegments.Length < 1 || string.IsNullOrWhiteSpace(pathSegments[0])) { await ReturnCustom422(context, "1111", "routeParam1 is required."); return; } // 校验routeParam2(对应路径第2段) if (pathSegments.Length < 2 || string.IsNullOrWhiteSpace(pathSegments[1])) { await ReturnCustom422(context, "2222", "routeParam2 is required."); return; } // 校验routeParam3(对应路径第4段) if (pathSegments.Length < 4 || string.IsNullOrWhiteSpace(pathSegments[3])) { await ReturnCustom422(context, "3333", "routeParam3 is required."); return; } } await _next(context); } private static async Task ReturnCustom422(HttpContext context, string customCode, string warning) { context.Response.StatusCode = StatusCodes.Status422UnprocessableEntity; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(new { customCode, warning }); } }
步骤2:注册中间件
在Program.cs中,将中间件注册到路由逻辑之后、端点映射之前:
var app = builder.Build(); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); // 注册自定义路由参数校验中间件 app.UseMiddleware<RouteParamValidationMiddleware>(); app.MapControllers(); app.Run();
测试验证
分别发起以下请求,即可得到预期的422响应:
- 请求1:
/abc/xyz//routeParam2/path/routeParam3?queryParam1=p1&queryParam2=p2→ 返回customCode=1111的422响应 - 请求2:
/abc/xyz/routeParam1//path/routeParam3?queryParam1=p1&queryParam2=p2→ 返回customCode=2222的422响应 - 请求3:
/abc/xyz/routeParam1/routeParam2/path/?queryParam1=p1&queryParam2=p2→ 返回customCode=3333的422响应
内容的提问来源于stack exchange,提问作者UndeadEmo
相关产品推荐
相关产品推荐

