如何在使用StaticFiles时在FastAPI根路径中加载与index.html不同的文件



这里有一个简单的静态FastAPI应用程序。使用此设置,即使根路径预期返回custom.htmlFileResponse,应用程序仍然返回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")

根据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文档:

"安装";意味着添加一个完整的"strong";独立的"应用程序特定路径,然后负责处理所有子路径

因此,任何以/开头的路径都将由该StaticFiles应用程序处理,并且由于在参数中指定了html=Trueindex.html将自动加载而不管创建一个指向根路径/的单独端点并尝试返回其他内容,如问题中给出的示例所示。

订单事项

例如,如果在定义@app.get("/")端点后移动了app.mount("/",StaticFiles(...,则会发现顺序很重要,并且由于端点是按顺序评估的,因此不会再自动加载index.html。请注意,在您的情况下,您可能会得到一个Internal Server Error,因为您的@app.get("/")端点将被调用并尝试查找custom.html,但如果该文件不在根/目录下,而是在/static目录下(如代码所示),那么您将得到File does not exist错误,因此,您应该返回FileResponse('static/custom.html')

即使删除了html=True,但将StaticFiles安装到根目录并在/端点之前定义,在尝试访问http://localhost:8000/时也会收到{"detail":"Not Found"}错误响应。这是因为/路由仍将由StaticFiles应用程序处理(如前所述),因此您需要指定要访问的文件(当不使用html=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请求,例如当您在浏览器的地址栏中键入URL,然后按Enter键,并且给定的路径与staticweb目录中的文件名不匹配),或{detail": "Method Not Allowed"}(如果您通过Swagger UI或其他客户端平台/应用程序发出POST请求)。如Starlette关于StaticFiles的文档中所述(同样参见StaticFiles类实现):

对于不匹配的请求,静态文件将使用404 Not found405 Method not allowed响应。在HTML模式下,如果404.html文件存在,它将显示为404响应。

因此,您应该将StaticFiles实例装载到不同的/唯一的路径,例如/static(即app.mount('/static', ...,如本答案顶部所示),或者,如果您仍然希望将StaticFiles实例装载到/路径,请在声明所有API端点后定义StaticFiles,例如:

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')

备注

每次加载网页时,浏览器都会缓存页面上的大部分内容,以缩短加载时间(用户下次加载页面时)。因此,如果您尝试前面提供的示例,即在每个API端点之前定义StaticFiles应用程序,然后使用同一浏览器会话,在所有API端点之后使用定义的StaticFiles应用程序尝试上面的示例,但浏览器仍然显示static/index.html文件的内容,而不是static/custom.html——当在浏览器中访问http://localhost:8000/时——这是由于浏览器从缓存加载网页。为了克服这个问题,你可以清除浏览器的缓存,或者在隐姓埋名窗口中打开网页(完成后关闭它),或者在浏览器中按Ctrl+F5,而不是只按F5(使用隐名或常规窗口),这将迫使浏览器从服务器检索网页,而不是从缓存加载网页。

关于FastAPI中端点的顺序,您可能也会发现这个答案很有用。

html=True选项

StaticFiles实例的html参数设置为True(即html=True),只需一行代码就可以简单地为web内容目录提供服务。如果您需要提供静态文件,例如package-docs目录,那么这就是方法。但是,如果您需要提供将被动态更新的不同HTML文件,并且您希望创建其他路由/端点,您应该更好地查看Templates(而不是FileResponse),以及将您的StaticFiles实例装载到不同的路径(例如/static),而不是根路径(并且不使用html=True)。

最新更新