ASP.NET Core API中如何对格式错误的URL段返回404状态码
在ASP.NET 6.0中保持Guid参数类型时将格式错误请求返回404的方案
先看原控制器代码:
[ApiController] public class FooController { [HttpGet("foo/{guid}")] public Guid Get(Guid guid) => guid; }
当请求合法Guid时返回200,但请求/foo/bar这类格式错误的路径时,默认返回400 Bad Request。我们需要在保持Guid参数类型的前提下,让这类请求返回404 Not Found。
以下是几种可行方案:
方案一:自定义Guid模型绑定器
创建一个针对Guid类型的模型绑定器,当绑定失败时直接返回404响应:
public class GuidNotFoundBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) { return Task.CompletedTask; } bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); string value = valueProviderResult.FirstValue; if (!Guid.TryParse(value, out Guid result)) { // 绑定失败,返回404 bindingContext.Result = ModelBindingResult.Failed(); bindingContext.HttpContext.Response.StatusCode = StatusCodes.Status404NotFound; return Task.CompletedTask; } bindingContext.Result = ModelBindingResult.Success(result); return Task.CompletedTask; } }
然后创建对应的绑定器提供程序:
public class GuidNotFoundBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context.Metadata.ModelType == typeof(Guid)) { return new BinderTypeModelBinder(typeof(GuidNotFoundBinder)); } return null; } }
最后在Program.cs中注册这个绑定器:
builder.Services.AddControllers(options => { options.ModelBinderProviders.Insert(0, new GuidNotFoundBinderProvider()); });
方案二:使用Action过滤器拦截模型验证错误
利用ApiController自动触发的模型验证,在过滤器中捕获Guid转换错误并替换为404:
public class GuidValidationToNotFoundFilter : IActionFilter { public void OnActionExecuting(ActionExecutingContext context) { if (!context.ModelState.IsValid) { // 检查是否有Guid转换相关的错误 var hasGuidParseError = context.ModelState.Values .Any(v => v.Errors.Any(e => e.Exception is FormatException && e.Exception.Message.Contains("Guid"))); if (hasGuidParseError) { context.Result = new NotFoundResult(); } } } public void OnActionExecuted(ActionExecutedContext context) { } }
在Program.cs中注册过滤器:
builder.Services.AddControllers(options => { options.Filters.Add<GuidValidationToNotFoundFilter>(); });
方案三:自定义路由约束
定义一个Guid路由约束,只有当路径段是合法Guid时才匹配该路由,否则路由不命中,自然返回404:
public class GuidRouteConstraint : IRouteConstraint { public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { if (values.TryGetValue(routeKey, out var value) && value is string stringValue) { return Guid.TryParse(stringValue, out _); } return false; } }
在Program.cs中注册约束:
builder.Services.AddRouting(options => { options.ConstraintMap.Add("guid", typeof(GuidRouteConstraint)); });
然后修改控制器的路由,使用自定义约束:
[ApiController] public class FooController { [HttpGet("foo/{guid:guid}")] // 使用自定义的guid约束 public Guid Get(Guid guid) => guid; }
这样当路径段不是合法Guid时,这个路由不会被匹配,ASP.NET会返回404。
内容的提问来源于stack exchange,提问作者Mark Seemann
相关产品推荐
相关产品推荐

