Skip to content

Swagger UI 接口文档实践 ​

在现代 Web 接口开发中,一份“准确、及时、可交互”的接口文档是团队协作的基石。Swagger UI (基于 OpenAPI 规范) 能够直接从代码注释中提取信息并生成在线文档,极大减少了文档维护的负担。

1. 核心价值与技术选型 ​

1.1 为什么选择 Swagger? ​

  • 自动化:基于代码反射和 XML 注释自动生成,确保文档与代码同步。
  • 可交互:内置 "Try it out" 功能,直接在网页上发起请求,无需 Postman 即可完成基础联调。
  • 标准化:遵循 OpenAPI Specification (OAS),生成的 JSON 可导出至其他平台(如 Apifox, YApi)。

1.2 Swagger vs. OpenAPI ​

  • OpenAPI:是一种规范(Specification),定义了如何描述 RESTful API。
  • Swagger:是一套工具集(Tools),包括 Swagger UI, Swagger Editor, Swagger Codegen。

1.3 .NET 生态主流方案对比 ​

方案特点推荐场景
Swashbuckle与 ASP.NET Core 深度集成,社区活跃度最高。大多数项目(首选)
NSwag提供更强大的客户端代码生成能力,支持 TypeScript/C# 客户端。需要自动生成 SDK 的项目

2. 基础配置与进阶实践 ​

2.1 基础配置 ​

csharp
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // 添加 Swagger UI
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo
        {
            Title = "TinyErp API",
            Version = "v1",
            Description = "TinyErp 接口说明文档",
            Contact = new OpenApiContact
            {
                Name = "hongjy",
                Email = "<hongjy1991@gmail.com>",
            },
            License = new OpenApiLicense
            {
                Name = "MIT",
            }
        });

        // 为 Swagger JSON 和 UI 设置 XML 文档注释路径
        var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
        var xmlPath = Path.Combine(basePath, "TinyErp.Admin.xml");

        c.IncludeXmlComments(Path.Combine(basePath, "TinyErp.Service.xml"));
        c.IncludeXmlComments(xmlPath);
        c.EnableAnnotations();
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 启用 Swagger 作为 JSON 终结点
    app.UseSwagger();

    // 启用 Swagger UI,并指定 Swagger JSON 终结点
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "TinyErp API v1");
        // 如果希望 Swagger UI 直接挂在根路径,可以打开下面这行:
        // c.RoutePrefix = string.Empty;
    });
}

2.2 进阶配置:支持 JWT 身份验证 ​

大多数生产环境的 API 都有认证限制。要在 Swagger UI 中直接测试带 Token 的接口,需添加如下配置:

csharp
services.AddSwaggerGen(c => {
    // 1. 定义安全方案 (SecurityScheme)
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
        Description = "请输入 JWT Token,格式为:Bearer {your_token}",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    // 2. 应用全局安全要求 (SecurityRequirement)
    c.AddSecurityRequirement(new OpenApiSecurityRequirement {
        {
            new OpenApiSecurityScheme {
                Reference = new OpenApiReference {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] {}
        }
    });
});

2.3 多版本 API 管理 (Versioning) ​

对于长期维护的项目,API 版本控制至关重要。建议配合 Microsoft.AspNetCore.Mvc.Versioning 使用。

csharp
services.AddApiVersioning(options => {
    options.ReportApiVersions = true;
    options.AssumeDefaultVersionWhenUnspecified = true;
    options.DefaultApiVersion = new ApiVersion(1, 0);
});

services.AddSwaggerGen(c => {
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "TinyErp API v1", Version = "v1" });
    c.SwaggerDoc("v2", new OpenApiInfo { Title = "TinyErp API v2", Version = "v2" });

    // 根据 Controller 的特性进行分组
    c.DocInclusionPredicate((docName, apiDesc) => {
        if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
        var versions = methodInfo.DeclaringType
            .GetCustomAttributes(true)
            .OfType<ApiVersionAttribute>()
            .SelectMany(attr => attr.Versions);

        return versions.Any(v => $"v{v.ToString()}" == docName);
    });
});

app.UseSwaggerUI(c => {
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "V1 Docs");
    c.SwaggerEndpoint("/swagger/v2/swagger.json", "V2 Docs");
});

2.4 UI 自定义与品牌化 (Custom UI) ​

如果觉得默认的 Swagger UI 太过单调,可以通过注入自定义 CSS 或 JS 来改变外观。

csharp
app.UseSwaggerUI(c => {
    c.InjectStylesheet("/swagger-ui/custom.css");
    c.InjectJavascript("/swagger-ui/custom.js");
    c.DocumentTitle = "思睿教学平台 - 接口文档";
});

3. 深度运维:常见坑位与避坑指南 ​

3.1 XML 注释路径与丢失问题 ​

问题:部署到 Linux 服务器后,Swagger 找不到注释。 原因:代码中硬编码了 Windows 风格的路径,或发布时未包含 XML 文件。 解决:使用 AppContext.BaseDirectory 动态获取路径,并在 .csproj 中配置发布包含。

xml
<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  <NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>

3.2 处理重复的 OperationId ​

问题:当不同 Controller 中存在同名方法时,Swagger 会抛出 Conflicting method/path combination 异常。 解决:使用 CustomSchemaIds 策略。

csharp
services.AddSwaggerGen(c => {
    c.CustomSchemaIds(type => type.FullName); // 使用全路径避免冲突
});

3.3 生产环境安全加固 ​

原则:绝不能在生产环境裸奔接口文档。 策略:

  1. 环境判断:仅在 Development 或 Staging 环境启用。
  2. 基础认证:为 Swagger UI 添加一层简单的 Basic Auth 保护。
csharp
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI(c => { ... });
    }
}

3.4 响应内容与模型 Schema 优化 ​

返回内容注释如果想在文档里展示,需要配合 Swashbuckle.AspNetCore.Annotations 组件。

csharp
[HttpGet("{id}")]
[SwaggerOperation(Summary = "获取用户信息", Description = "根据主键 ID 获取用户的详细资料")]
[SwaggerResponse(200, "成功返回用户信息", typeof(UserDto))]
public IActionResult GetUser(int id) { ... }

4. 扩展工具与生态集成 ​

4.1 OpenAPI 规范导出 ​

生成的 swagger.json 是标准化的,可以轻松对接以下生态:

  • Apifox / YApi:直接导入 JSON 地址,实现更强大的文档管理与 Mock 功能。
  • Postman:通过 Import -> Link 导入,快速生成测试集合。
  • 代码生成器:使用 NSwag 或 Swagger Codegen 根据 JSON 自动生成前端 TypeScript 接口代码或 SDK。

4.2 性能调优建议 ​

  • 缓存 XML:大型项目 XML 文件巨大,读取缓慢。在容器化部署时,建议将 XML 预打包进镜像。
  • 按需分组:避免一个 v1 文档包含几百个接口,按模块拆分(如 auth, order, product)可以显著提升 UI 加载速度。

5. 总结与回顾 ​

Swagger UI 不仅仅是一个展示页面,它是 “契约驱动开发” (Contract-First Development) 的核心工具。

  • 对于开发:它是自测利器,"Try it out" 减少了对 Postman 的依赖。
  • 对于前端:它是可靠的契约,字段类型、是否必填一目了然。
  • 对于运维:它是生产环境的“禁区”,必须通过环境配置或权限控制进行保护。

6. 参考资料 ​

方舟 · Ark