把 FastAPI 默认文档界面改成品牌色:从零配置到自托管的三条实用路径
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
/docs 界面还是默认蓝,却已经跟着截图发给了客户。本文梳理 FastAPI 文档界面定制的三条实用路径,从 3 行参数调整到离线自托管,只动 CSS 和配置,不碰业务代码。
先跑起来:5 分钟最小可用配置
要立刻看到变化,就三步:下载官方 Swagger UI 的 css、挂一个静态目录、把 /docs 的 css 地址指过去。先拿文件,内网环境请在线机器上执行好再拷进去:
# 先拿官方 css,自定义规则之后会追加在这个文件末尾 mkdir -p static curl -o static/swagger-ui.css https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css然后重写 /docs 的生成逻辑,核心只多了一行参数:
from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.openapi.docs import get_swagger_ui_html app = FastAPI(docs_url=None) # 关掉内置文档,让位给自定义 app.mount("/static", StaticFiles(directory="static"), name="static") @app.get("/docs", include_in_schema=False) async def custom_docs(): # 只换 css 地址,其余行为与默认文档一致 return get_swagger_ui_html( openapi_url=app.openapi_url, title=app.title + " - Swagger UI", swagger_css_url="/static/swagger-ui.css", )把下面路径 B 的品牌规则追加到这份 css 末尾、刷新页面,顶栏和标题就从默认蓝变成你自己的颜色。原理一句话:本质上把默认 CSS 的<link>加载地址换成了自托管文件——框架只有一个样式表槽位,加规则只能换文件,不能加标签。
它到底改了哪一层 🔧
文档界面的 HTML 不是静态文件,浏览器每次请求 /docs 时,都由fastapi/openapi/docs.py里的get_swagger_ui_html现拼出来。页面<head>里只有一个<link>,地址来自swagger_css_url(默认是 jsdelivr 的 CDN 地址);swagger_ui_parameters字典里的键值则会与内置默认值合并(你的值覆盖默认值),再序列化成 JSON 注入SwaggerUIBundle的初始化参数。所以"改样式"只有两个出口:换 CSS 地址决定颜色,调 JS 参数决定行为。
细节可查 docs/en/docs/how-to/configure-swagger-ui.md(参数配置)与 docs/en/docs/how-to/custom-docs-ui-assets.md(自托管)两个官方章节。
三条定制路径,按成本选
三条路径互不依赖,按你能接受多少"后续维护量"挑一条,不用全做。
路径 A|零 CSS,纯参数配置
适用场景:只想开关功能项,不碰品牌色。
app = FastAPI( swagger_ui_parameters={ "syntaxHighlight": {"theme": "none"}, # monokai(默认)/ none "deepLinking": False, # 关掉接口标题的锚点跳转 } )高频坑:Swagger UI 的syntaxHighlight.theme只认monokai和none,写 arta、nord 这类名字会被静默忽略;另外参数值必须能序列化成 JSON,传 Python 函数或对象会直接报错。
路径 B|挂载静态目录,注入自定义 CSS
适用场景:品牌色、顶栏、按钮这类一切"改样子"的活。
/* 品牌规则追加在官方 swagger-ui.css 文件末尾,同名选择器后者生效 */ .swagger-ui .topbar { background: #1f3a5f; } .swagger-ui .topbar .btn.authorize { background: #1f3a5f; } .swagger-ui .info .title { color: #1f3a5f; }注意:这里换上去的 css 是整体替换文件,不是补丁。只写这三行而不带官方 css,页面会直接裸奔成黑白骨架,见下方踩坑记录。
路径 C|整体替换资源:离线自托管与 CDN 版本锁定
适用场景:生产内网、合规审计,或者想把文档界面钉死在某个版本、别让 CDN 升级悄悄改样式。
在路径 B 基础上,把swagger-ui-bundle.js、redoc.standalone.js也下载到 static/,js 和 css 全部指向本地文件(get_redoc_html的 import 与上面同理):
@app.get("/docs", include_in_schema=False) async def custom_docs(): return get_swagger_ui_html( openapi_url=app.openapi_url, title=app.title + " - Swagger UI", swagger_js_url="/static/swagger-ui-bundle.js", # 本地文件,版本锁死 swagger_css_url="/static/swagger-ui.css", oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, ) @app.get("/redoc", include_in_schema=False) async def custom_redoc(): return get_redoc_html( openapi_url=app.openapi_url, title=app.title + " - ReDoc", redoc_js_url="/static/redoc.standalone.js", with_google_fonts=False, # 内网加载不到外部 Google Fonts )如果文档界面要用 OAuth2 登录,记得补一条返回get_swagger_ui_oauth2_redirect_html()的重定向路由,否则 Authorize 按钮会 404。
| 路径 | 需要维护的额外文件 | 改动量 | 典型场景 |
|---|---|---|---|
| A 纯参数 | 无 | 3 行配置 | 内部团队、功能开关 |
| B 注入 CSS | 1 个 css(官方+自有规则) | 1 条路由 + 静态目录 | 品牌色、对外截图 |
| C 自托管 | 2-3 个官方 js/css | 改写两条路由 | 内网离线、合规、版本锁定 |
踩坑记录:这些问题会耗掉你一小时 📌
TypeError: FastAPI.__init__() got an unexpected keyword argument 'swagger_css_url':把 css 地址直接传给FastAPI()会报这个错。原因:swagger_css_url是get_swagger_ui_html的参数,FastAPI()构造器不暴露它。解决:docs_url=None关掉内置文档,自己挂 /docs 路由时再传地址。- 换了 css 后页面完全裸样式,只剩黑白骨架:
swagger_css_url是替换槽位而不是追加槽位,页面上唯一的样式表就是它。解决:官方 swagger-ui.css 和自有规则放同一个文件,自有规则放文件末尾。 - 主题名写了 arta、nord 却毫无效果,也不报错:Swagger UI 的
syntaxHighlight.theme只识别monokai和none,其他值被静默忽略。解决:只用这两个值;更细的颜色调整走路径 B。 - ReDoc 自托管了,内网下仍发外部请求:ReDoc 的 CSS 内联在
redoc.standalone.js里,页面默认还会去拉 Google Fonts。解决:js 自托管并传with_google_fonts=False,外部依赖才算清干净。
什么时候不用折腾
文档只给内部团队看和调试、截图不出门的话,默认 jsdelivr CDN 的样式完全够用,最多配一条路径 A 的开关。只有当"截图会发给客户、颜色必须跟 VI 一致",或者内网不通外网、合规要求资源可审计时,才值得走路径 B 和 C——否则维护官方文件的成本不划算。
下次文档截图跟着发版说明出门时,顶栏已经是你们家的颜色了。
【免费下载链接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production项目地址: https://gitcode.com/GitHub_Trending/fa/fastapi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考