FastAPI访问/docs接口文档显示空白、js/css无法加载

2024-07-21 1126阅读

如图:

FastAPI访问/docs接口文档显示空白、js/css无法加载

原因是FastAPI的接口文档默认使用https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css

和https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js

来渲染页面,而这两个URL是外网的CDN,在国内响应超慢,导致请求超时了。

## How to fix:

**NOTE**:  有直达外网VPN的话,直接开启VPN就可以,一行代码都不用改。

官方文档给出的解决方案是定制文档响应函数Custom Docs UI Static Assets (Self-Hosting) - FastAPI

from fastapi import FastAPI
from fastapi.openapi.docs import (
    get_redoc_html,
    get_swagger_ui_html,
    get_swagger_ui_oauth2_redirect_html,
)
app = FastAPI(docs_url=None, redoc_url=None)
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
    return get_swagger_ui_html(
        openapi_url=app.openapi_url,
        title=app.title + " - Swagger UI",
        oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
        swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
        swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
    )
@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False)
async def swagger_ui_redirect():
    return get_swagger_ui_oauth2_redirect_html()
@app.get("/redoc", include_in_schema=False)
async def redoc_html():
    return get_redoc_html(
        openapi_url=app.openapi_url,
        title=app.title + " - ReDoc",
        redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js",
    )
@app.get("/users/{username}")
async def read_user(username: str):
    return {"message": f"Hello {username}"}

这虽然能解决问题,但会导致每次创建新项目,都需要拷贝这些相似的代码,不够pythonic

## More efficient

花了好几天的时间,写了一个开源库fastapi-cdn-host,把它变沉一行代码就能搞定的:

# pip install fastapi_cdn_host
import fastapi_cdn_host
from fastapi import FastAPI
app = FastAPI()
# 启动app时会自动将CDN更换为响应速度较快的那个
fastapi_cdn_host.patch_docs(app)

注:如果是要支持离线文档,只需在main.py的同级目录下,放置static文件夹(里面需包含swagger-ui-bundle.js和swagger-ui.css),启动时就会自动挂载并使用它。

BTW:写这个库本身没花多少时间,但是写它的单元测试,真真是花了很多很多时间。由于实际测试的场景也不是很多,难免会有纰漏,欢迎来提issue: https://github.com/waketzheng/fastapi-cdn-host

> 仅支持0.100.0以上版本的fastapi,老版本的请直接用官网示例。 

## 2024.05.12 补充:一个详细一点的示例

- main.py

#!/usr/bin/env python
import os
import sys
from contextlib import asynccontextmanager
from datetime import datetime
import fastapi_cdn_host
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
__version__ = "1.0.0"
@asynccontextmanager
async def lifespan(app: FastAPI):
    # 注册数据库、挂载Redis等……
    yield
app = FastAPI(, lifespan=lifespan, version=__version__)
fastapi_cdn_host.patch_docs(app)
@app.get("/", include_in_schema=False)
async def root(request: Request) -> RedirectResponse:
    """首页直接跳转到文档"""
    return RedirectResponse("/docs")
@app.get("/robots.txt", include_in_schema=False)
async def robots_txt():
    """声明不允许爬虫访问"""
    return """
    User-agent: *
    Disallow: /
    """
@app.get("/app")
async def app_info(request: Request) -> dict[str, str | dict | datetime | None]:
    """展示客户端IP、服务器时间等信息"""
    headers = dict(request.headers)
    ip = getattr(request.client, "host", "")
    url = request.url
    return {
        "your ip": ip,
        "version": __version__,
        "now": datetime.now(),
        "headers": headers,
        "path": request.url.path,
        "url": {"scheme": url.scheme, "hostname": url.hostname, "port": url.port},
    }
def _runserver() -> int:
    """This is for debug mode to start server. For prod, use supervisor+gunicorn instead."""
    return os.system("fastapi dev")
if __name__ == "__main__":  # pragma: no cover
    sys.exit(_runserver())
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]