如何在使用 StaticFiles 时在 FastAPI 根路径中加载除 index.html 不同的文件?
- 2024-12-31 08:37:00
- admin 原创
- 111
问题描述:
这是一个简单的静态 FastAPI 应用程序。使用此设置,即使根路径预计返回FileResponse
,custom.html
应用程序仍会返回index.html
。如何让根路径工作并渲染custom.html
?
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
app = FastAPI()
app.mount(
"/",
StaticFiles(directory="static", html=True),
name="static",
)
@app.get("/")
async def index() -> FileResponse:
return FileResponse("custom.html", media_type="html")
解决方案 1:
根据 Starlette文档:
静态文件
签名:
StaticFiles(directory=None, packages=None, check_dir=True)
html
- 以 HTML 模式运行。index.html
如果文件存在,则自动加载目录。
此外,如您提供的代码片段所示,您已挂载StaticFiles
到根目录(即/
),而不是例如/static
(或其他路径名),如下所示:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount('/static', StaticFiles(directory='static'), name='static')
根据 FastAPI文档:
“挂载”意味着在特定路径中添加完整的“独立”应用程序,然后负责处理所有子路径。
因此,以 开头的任何路径都/
将由该应用程序处理StaticFiles
,并且由于html=True
在参数中指定,index.html
将自动加载;无论是否创建指向根路径的单独端点/
并尝试返回其他内容,如您的问题中给出的示例所示。
顺序很重要
例如,如果您在定义端点后移动了app.mount("/",StaticFiles(...
行,则会看到顺序很重要,并且不会再自动加载,因为端点是按顺序评估的。请注意,在您的情况下,您可能会得到一个,因为您的端点将被调用并尝试找到,但如果此文件不在根目录下,而是在目录下(如您的代码所示),那么您将收到错误,因此,您应该返回。@app.get("/")
`index.htmlInternal Server Error
@app.get("/")custom.html
//static
File does not exist`FileResponse('static/custom.html')
即使你删除了html=True
,但仍将其StaticFiles
挂载到根目录并在端点之前定义,尝试访问 时/
仍会收到错误响应。这是因为路由仍将由应用程序处理(如前所述),因此你需要指定要访问的文件(当未使用时),例如 。即使你在代码中定义了其他端点(例如、、),只要挂载到根目录(即)并在代码中所有其他端点之前定义,例如:{"detail":"Not Found"}
`http://localhost:8000//
StaticFileshtml=True
http://localhost:8000/index.html/register
/login/hello
StaticFiles`/
app.mount('/', StaticFiles(directory='static'), name='static')
@app.post('/register')
async def register():
pass
@app.post('/login')
async def login():
pass
@app.get('/hello')
async def hello():
pass
对这些路由的每个请求都将再次由应用程序处理StaticFiles
,因此会导致错误响应,例如{"detail":"Not Found"}
(如果您发送GET
请求,例如当您在 Web 浏览器的地址栏中键入 URL 然后按下键时Enter
,给定的路径与 Web 目录中的文件名不匹配static
),或者{detail": "Method Not Allowed"}
(如果您POST
通过 Swagger UI 或其他客户端平台/应用程序发出请求)。如Starlette 的文档StaticFiles
中所述(另请参阅StaticFiles
类实现):
对于不匹配的请求,静态文件将响应
404 Not found
或响应。在 HTML 模式下,如果
文件存在,它将显示为 404 响应。405 Method not allowed
`404.html`
因此,您应该将StaticFiles
实例安装到不同的/唯一的路径,例如/static
(即app.mount('/static', ...
,如该答案顶部所示),或者,如果您仍然想将实例安装StaticFiles
到/
路径,请StaticFiles
在声明所有 API 端点后定义,例如:
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
app = FastAPI()
@app.post('/register')
async def register():
pass
@app.post('/login')
async def login():
pass
@app.get('/hello')
async def hello():
pass
@app.get('/')
async def index():
return FileResponse('static/custom.html')
app.mount('/',StaticFiles(directory='static', html=True), name='static')
笔记
每次加载网页时,Web 浏览器都会缓存页面上的大部分内容,以缩短加载时间(下次用户加载页面时)。因此,如果您尝试了前面提供的示例,即在每个 API 端点之前StaticFiles
定义应用程序,然后使用相同的浏览器会话,您尝试了上述示例,其中应用程序定义在所有 API 端点之后,但浏览器仍然显示文件的内容而不是-在浏览器中访问时 - 这是因为浏览器从缓存中加载网页。为了解决这个问题,您可以清除浏览器的缓存,或者在隐身窗口中打开网页(完成后关闭它),或者只需在浏览器中按+而不是(使用隐身或常规窗口),这将强制浏览器从服务器检索网页而不是从缓存中加载。StaticFiles
`static/index.htmlstatic/custom.html
http://localhost:8000/Ctrl
F5`F5
关于 FastAPI 中端点的顺序,您可能还会发现这个答案很有帮助。
选择html=True
将实例html
的参数设置为(即)提供了一种只需一行代码即可提供 Web 内容目录的简单方法。如果您只需要提供静态文件(例如包文档目录),那么这就是您要走的路。但是,如果您需要提供将动态更新的不同 HTML 文件,并且您希望创建其他路由/端点,您最好查看(不是),并将您的实例安装到不同的路径(例如),而不是根路径(并且不使用)。StaticFiles
`Truehtml=True
Templates
FileResponseStaticFiles
/static`html=True