FastAPI Web 开发菜鸟教程:静态文件服务

Web 开发中,我们常常需要提供静态文件,比如图片、CSS 文件、JavaScript 文件等。FastAPI 是一个快速(高性能)的 Python Web 框架,它允许我们轻松地实现静态文件服务。

安装必要的库

首先,我们需要安装 fastapi 和 uvicorn(一个 ASGI 服务器,用于运行 FastAPI 应用)。可以使用以下命令进行安装:

pip install fastapi uvicorn

创建静态文件目录

在项目根目录下创建一个名为 static 的文件夹,用于存放静态文件。例如,我们在 static 文件夹中放入一张名为 shanhaimoyuren.jpg 的图片,代表“山海摸鱼人”。

编写 FastAPI 代码

以下是一个简单的 FastAPI 应用,用于提供静态文件服务:

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

# 创建 FastAPI 应用实例
app = FastAPI()

# 挂载静态文件目录
# 将 /static 路径映射到项目根目录下的 static 文件夹
app.mount("/static", StaticFiles(directory="static"), name="static")

# 定义一个简单的路由
@app.get("/")
def read_root():
    # 返回一个包含静态文件链接的 HTML 响应
    return {
        "message": "欢迎来到山海摸鱼人的世界!打开下面的链接查看图片",
        "image_url": "http://127.0.0.1:8000/static/shanhaimoyuren.jpg"
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

from fastapi.staticfiles import StaticFiles:导入 StaticFiles 类,用于处理静态文件服务。

app.mount("/static", StaticFiles(directory="static"), name="static"):使用 mount 方法将 /static 路径映射到项目根目录下的 static 文件夹。这样,当客户端访问 /static 开头的路径时,FastAPI 会自动从 static 文件夹中查找对应的文件。

@app.get("/"):定义一个根路径的 GET 请求处理函数,返回一个包含静态文件链接的 JSON 响应。

测试静态文件服务
打开浏览器,访问 http://127.0.0.1:8000,你会看到一个 JSON 响应,其中包含一个图片链接。访问链接,就可以看到 static 文件夹中的 shanhaimoyuren.jpg 图片。

图片

404 错误处理

对静态文件相关的错误情况进行处理。比如,当请求的静态文件不存在时,FastAPI 默认会返回404状态码,但可以自定义异常处理,给用户更友好的提示信息:

from fastapi import FastAPI, HTTPException
from fastapi.staticfiles import StaticFiles
from starlette.responses import JSONResponse

app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")


@app.exception_handler(404)
asyncdef custom_404(request, exc):
    if request.url.path.startswith("/static"):
        return JSONResponse(
            status_code=404,
            content={"message": "您请求的静态文件不存在,山海摸鱼人也找不到啦!"}
        )
    return JSONResponse(
        status_code=404,
        content={"message": "页面未找到"}
    )


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

浏览器访问 http://127.0.0.1:8000/图片浏览器访问 http://127.0.0.1:8000/static/1.jpg图片

缓存控制

为了提高性能,可以设置静态文件的缓存头。对于不经常变动的静态文件(如一些基础的CSS框架文件、图标文件等),设置合适的缓存时间可以减少客户端重复请求,降低服务器负载。

原理
HTTP协议定义了一些用于缓存控制的响应头字段,常见的有Cache-ControlExpires等。其中,Cache-Control 是一个通用首部字段,用于控制缓存的行为,它可以指定缓存的时间、缓存的范围(如是否允许公共缓存、私有缓存)等;Expires 则指定了一个具体的过期时间。一般推荐使用 Cache-Control,因为它比 Expires 更灵活,并且能处理更复杂的缓存场景。

使用 StaticFiles 的 headers 参数
可以在挂载静态文件目录时,通过 StaticFiles 类的 headers 参数来设置缓存控制的响应头。以下是示例代码:

from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles

# 创建FastAPI应用实例
app = FastAPI()

# 设置缓存控制的响应头,这里设置最大缓存时间为1小时(3600秒)
cache_headers = {"Cache-Control": "public, max-age=3600"}

# 挂载静态文件目录,并应用缓存控制头
app.mount("/static", StaticFiles(directory="static", headers=cache_headers), name="static")

cache_headers = {"Cache-Control": "public, max-age=3600"}:定义了一个字典,其中键为 Cache-Control,值为缓存控制的策略。public 表示该响应可以被任何缓存(如浏览器缓存、中间代理缓存等)存储;max-age=3600 表示缓存的最大时间为3600秒(即1小时),在这1小时内,客户端再次请求相同的静态文件时,会直接使用本地缓存,而不会向服务器发送请求。

app.mount("/static", StaticFiles(directory="static", headers=cache_headers), name="static"):在挂载静态文件目录时,将定义好的缓存头传递给 headers 参数,这样所有通过 /static 路径访问的静态文件都会带有该缓存控制头。

不同类型静态文件的不同缓存策略
对于不同类型的静态文件,可能需要不同的缓存策略。例如,对于一些经常更新的 JavaScript 文件,可以设置较短的缓存时间;而对于一些很少变动的 CSS 框架文件,可以设置较长的缓存时间。可以通过多次挂载不同的静态文件目录,并分别设置不同的缓存头来实现:

# 对于经常更新的js文件,设置较短的缓存时间(如10分钟)
js_cache_headers = {"Cache-Control": "public, max-age=600"}
app.mount("/static/js", StaticFiles(directory="static/js", headers=js_cache_headers), name="js_static")

# 对于很少变动的css框架文件,设置较长的缓存时间(如1天)
css_cache_headers = {"Cache-Control": "public, max-age=86400"}
app.mount("/static/css", StaticFiles(directory="static/css", headers=css_cache_headers), name="css_static")

分别为 JavaScript 文件和 CSS 文件设置了不同的缓存控制头,这样客户端在请求不同类型的静态文件时,会根据相应的缓存策略进行缓存。

实际效果
当客户端(如浏览器)第一次请求静态文件时,服务器会返回文件内容,并在响应头中包含设置的缓存控制信息。客户端会根据这些信息将文件缓存到本地。在缓存有效期内,客户端再次请求相同的文件时,会直接从本地缓存中读取,而不会向服务器发送请求,从而减少了网络请求,提高了页面加载速度。当缓存过期后,客户端会再次向服务器发送请求,获取最新的文件内容。

来源:山海摸鱼人

THE END