FastAPI中如何随HTML文件渲染CSS/JS/Images静态资源?
问题现象
启动FastAPI服务后,访问http://127.0.0.1:8765/能正常渲染HTML页面,但CSS、JS等静态资源全部加载失败。浏览器控制台显示:资源请求路径错误,期望路径为http://127.0.0.1:8765/styles.xxx.css,实际请求路径却变成了http://127.0.0.1:8765/static/styles.xxx.css。
相关代码与文件结构
1. main.py 完整代码
import uvicorn import os import webbrowser from fastapi import FastAPI from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse app = FastAPI( title="UI", description="This is to test", ) app.add_middleware( CORSMiddleware, allow_origins=['*'], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) static_dir = os.path.join(os.path.dirname(__file__), "static") app.mount("/",StaticFiles(directory=static_dir, html=True),name="static") def start_server(): uvicorn.run( "ui.main:app", host="0.0.0.0", port=8765, log_level="debug", reload=True, ) if __name__ == "__main__": start_server()
通过test.py作为模块启动:
from ui import main if __name__ == "__main__": main.start_server()
2. index.html 完整代码(Angular打包生成)
<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title>WingmanUi</title> <base href="static/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="stylesheet" href="styles.87afad25367d1df4.css" media="print" onload="this.media='all'"> </head> <body> This is to test <script src="runtime.7f95ee6540776f88.js" type="module"></script> <script src="polyfills.a246e584d5c017d7.js" type="module"></script> <script src="main.4f51d0f81827a3db.js" type="module"></script> </body> </html>
3. 文件结构
ui - static - index.html - styles.87afad25367d1df4.css - runtime.7f95ee6540776f88.js - polyfills.a246e584d5c017d7.js - main.4f51d0f81827a3db.js - main.py - __init__.py
问题根源
问题出在index.html的<base href="static/">标签上。这个标签会给所有相对路径的资源请求自动加上static/前缀,但你的FastAPI已经把static目录直接挂载到了根路径/下,资源实际在根路径即可访问,不需要额外的static/前缀,导致路径不匹配。
解决方案
方案1:修改index.html的base标签(推荐)
将<base href="static/">改为<base href="/">,这样所有相对路径的资源都会直接请求根路径,和FastAPI的静态资源挂载路径完全匹配。
修改后的index.html头部片段:
<head> <meta charset="utf-8"> <title>WingmanUi</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 其他标签保持不变 --> </head>
方案2:调整FastAPI的静态资源挂载路径(可选)
如果不想修改Angular打包生成的HTML文件,可以调整FastAPI的静态资源挂载路径,并添加根路径路由返回index.html:
# 替换原有的mount代码 static_dir = os.path.join(os.path.dirname(__file__), "static") app.mount("/static", StaticFiles(directory=static_dir), name="static") # 添加根路径路由,返回index.html @app.get("/") async def index(): return FileResponse(os.path.join(static_dir, "index.html"), media_type='text/html')
这种方式下,<base href="static/">的前缀会和FastAPI的挂载路径匹配,资源就能正常加载。
额外注意点
原代码中同时挂载根路径为静态目录,又定义了@app.get("/")返回FileResponse,这会导致路由冲突:FastAPI的静态文件中间件优先级更高,所以@app.get("/")的路由实际上不会生效,直接由StaticFiles返回index.html。采用方案1时,保留原挂载方式即可,无需额外添加根路由。
内容的提问来源于stack exchange,提问作者Rakesh Shetty

