You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core Minimal API如何通过请求头实现接口版本控制?

ASP.NET Core Minimal API 基于请求头的版本控制实现及Swagger支持

一、实现基于请求头的路由区分

你的代码中两个/save路由被视为重复,是因为它们的路径完全一致,ASP.NET Core无法自动区分。要实现基于X-Api-Version请求头的路由匹配,有两种优雅的实现方式:

方法1:自定义路由约束

通过自定义路由约束,让ASP.NET Core根据请求头值匹配对应的处理程序:

  1. 创建自定义约束类:
public class ApiVersionHeaderConstraint : IRouteConstraint
{
    private readonly string _requiredVersion;

    public ApiVersionHeaderConstraint(string requiredVersion)
    {
        _requiredVersion = requiredVersion;
    }

    public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        return httpContext.Request.Headers.TryGetValue("X-Api-Version", out var version) 
               && version.Equals(_requiredVersion, StringComparison.OrdinalIgnoreCase);
    }
}
  1. 注册约束到路由配置:
builder.Services.Configure<RouteOptions>(options =>
{
    options.ConstraintMap.Add("apiVersion", typeof(ApiVersionHeaderConstraint));
});
  1. 定义带约束的路由:
app.MapPost("/save", ([FromBody] SaveRequestV1 request) => "Do something for v1")
   .WithMetadata(new RouteConstraintMetadata("apiVersion", "v1"));

app.MapPost("/save", ([FromBody] SaveRequestV2 request) => "Do another thing for v2")
   .WithMetadata(new RouteConstraintMetadata("apiVersion", "v2"));

方法2:使用MapWhen筛选请求

如果不想自定义约束,可以用MapWhen按请求头分组处理:

// 处理v1版本请求
app.MapWhen(context => 
    context.Request.Headers.TryGetValue("X-Api-Version", out var version) 
    && version.Equals("v1", StringComparison.OrdinalIgnoreCase), v1App =>
{
    v1App.MapPost("/save", ([FromBody] SaveRequestV1 request) => "Do something for v1");
});

// 处理v2版本请求
app.MapWhen(context => 
    context.Request.Headers.TryGetValue("X-Api-Version", out var version) 
    && version.Equals("v2", StringComparison.OrdinalIgnoreCase), v2App =>
{
    v2App.MapPost("/save", ([FromBody] SaveRequestV2 request) => "Do another thing for v2");
});

二、Swagger支持基于请求头的版本控制

Swagger完全支持这种版本控制方式,只需配置多版本文档并添加请求头参数:

  1. 配置Swagger生成器:
builder.Services.AddSwaggerGen(options =>
{
    // 注册v1和v2版本的文档
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    options.SwaggerDoc("v2", new OpenApiInfo { Title = "My API", Version = "v2" });

    // 添加全局请求头参数过滤器
    options.OperationFilter<ApiVersionHeaderFilter>();
});

// 自定义操作过滤器,自动添加X-Api-Version请求头
public class ApiVersionHeaderFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var apiVersion = context.ApiDescription.GroupName;
        operation.Parameters.Add(new OpenApiParameter
        {
            Name = "X-Api-Version",
            In = ParameterLocation.Header,
            Required = true,
            Schema = new OpenApiSchema { Type = "string", Default = new OpenApiString(apiVersion) }
        });
    }
}
  1. 配置Swagger UI中间件:
app.UseSwagger();
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/swagger/v1/swagger.json", "My API v1");
    options.SwaggerEndpoint("/swagger/v2/swagger.json", "My API v2");
});

这样在Swagger UI中选择不同版本的文档时,会自动填充对应的X-Api-Version请求头,也可以手动修改值测试不同版本接口。

补充说明

  • 你尝试的[FromHeader(Name = "X-Api-Version:regex(^1$)")]写法不被支持,FromHeader的Name属性仅用于指定请求头名称,不支持正则约束逻辑。
  • 若使用SaveVersion枚举,也可以在同一个路由处理程序中分支判断版本,但这种方式会将不同版本的业务逻辑耦合在一起,不如上述两种方式清晰。

内容的提问来源于stack exchange,提问作者Endy Tjahjono

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:46:34