news 2026/7/3 5:22:20

FastAPI静态资源、跨域与后台任务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FastAPI静态资源、跨域与后台任务

转载说明:文章最新在掘金上发用户名为CaffeinePro,CSDN是我最早加入的社区,但由于vip文章的原因不想然文章付费所以选择首发在掘金。

假设现在有个需求,要做一个最小可用的用户注册功能:

  1. 前端页面展示Logo、样式,用户填写手机号和昵称后提交;
  2. 前端运行在http://127.0.0.1:5500,API在http://127.0.0.1:8000——跨域
  3. 注册成功后API立刻返回,但还要在后台发欢迎短信、写审计日志——不能让用户等

这三个需求,正好对应 FastAPI 的三块能力:静态资源挂载CORS 中间件BackgroundTasks

推荐项目结构

demo/ ├── main.py # FastAPI入口,CORS、静态挂载、注册接口 ├── tasks/ │ └── background.py # 后台任务,发短信、写日志 ├── static/ │ ├── css/style.css # 样式 │ ├── js/app.js # 前端fetch(含自定义请求头) │ ├── images/logo.svg # Logo图片 │ └── demo.html # 注册页(也可用 Live Server 打开) ├── logs/ # 运行后自动生成:注册日志 ├── requirements.txt └── test_main.http # HTTP 测试用例

一、挂载本地静态文件夹

  • /static/css/style.css—页面样式
  • /static/js/app.js—提交表单的JavaScript
  • /static/images/logo.svg—页面图标

这些文件放在服务器本地磁盘,不需要经过Python业务逻辑,FastAPI用StaticFiles直接映射URL到目录。
需要在main中实现代码实现代码:

frompathlibimportPathfromfastapi.staticfilesimportStaticFiles STATIC_DIR=Path(__file__).resolve().parent/"static"app.mount("/static",StaticFiles(directory=str(STATIC_DIR)),name="static")

定义静态目录时,代码通过Path(__file__).resolve().parent/"static"构建路径:__file__代表当前脚本文件,resolve()将其彻底解析为绝对路径并清除符号链接,parent获取该文件所在的上级目录,最后利用/运算符将static子文件夹拼接到其后,生成一个确定的Path对象。这一做法的核心目的是确保静态文件目录与项目代码处于同一级目录下,无论应用从何处启动,路径定位始终可靠,从而增强了项目的可移植性和部署时的稳定性。

挂载操作通过app.mount()方法实现,它将路由前缀/static与本地静态目录绑定,使得客户端访问http://域名/static/xxx时能够直接获取对应的本地文件资源。需要注意的是,StaticFilesdirectory参数要求传入字符串形式,因此必须用str(STATIC_DIR)显式转换;同时,指定name="static"为挂载点命名,便于在应用内部通过request.url_for("static", path="...")动态反向生成静态资源的完整 URL,既保证了静态文件的正常服务,也提升了代码中资源引用的灵活性与可维护性。
访问http://127.0.0.1:8000/static/images/logo.svg时,FastAPI会从static/images/logo.svg读取文件并返回,并自动设置合适的Content-Type

返回HTML页面

FileResponse返回demo.html,示例代码为:

fromfastapi.responsesimportFileResponse@app.get("/demo")asyncdefdemo_page():returnFileResponse(STATIC_DIR/"demo.html")

StaticFiles适合css/js/图片等纯静态资源,单个HTML页面用FileResponse更灵活可以加鉴权、动态变量等。
下面是几点注意事项

要点说明
mount路径/static挂载后,目录内css/style.css对应URL/static/css/style.css
挂载顺序mount的路由优先级低于普通@app.get路由;避免路径冲突
生产环境大量静态资源建议走Nginx/CDN,Python进程专注API
缓存生产可在Nginx层加Cache-Control,开发阶段--reload即可

二、CORS 跨域中间件完整配置

前端在http://127.0.0.1:5500,API在http://127.0.0.1:8000——协议相同、域名相同、端口不同,浏览器判定为跨域
若不做处理,浏览器控制台会出现:

Access to fetch at 'http://127.0.0.1:8000/api/users/register' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy

在本案例中的代码示例为:

fromfastapi.middleware.corsimportCORSMiddleware ALLOWED_ORIGINS=["http://127.0.0.1:5500","http://localhost:5500","http://127.0.0.1:5173",# Vite的默认端口"http://localhost:5173",]app.add_middleware(CORSMiddleware,allow_origins=ALLOWED_ORIGINS,allow_credentials=True,allow_methods=["GET","POST","PUT","DELETE","OPTIONS"],allow_headers=["*"],expose_headers=["X-Request-Id"],max_age=600,)

下面是对上面代码的参数解析:

参数作用案例取值理由
allow_origins允许哪些源访问开发环境列出前端地址;生产写具体域名
allow_credentials是否允许携带Cookie登录态场景需要True
allow_methods允许的HTTP方法必须包含OPTIONS(预检用)和POST
allow_headers允许客户端发送的请求头Demo前端发了X-Client-Version
expose_headers允许JS读取的响应头X-Request-Id用于链路追踪
max_age预检结果缓存秒数600秒内重复请求不再发OPTIONS

前端预检请求OPTIONS的坑

constres=awaitfetch(`${API_BASE}/api/users/register`,{method:"POST",headers:{"Content-Type":"application/json","X-Client-Version":"demo-1.0",// 非简单头触发预检},body:JSON.stringify(payload),});

浏览器在真正发POST之前,会先发送OPTIONS预检请求,询问服务器:"我能不能从5500端口、用POST、带X-Client-Version头访问你。"整体实际的流程如下图所示:

常见的踩坑与修改如下表所示:

现象原因修复
OPTIONS 404路由只注册了POST,没处理OPTIONS使用CORSMiddleware,它会自动处理OPTIONS
预检通过但POST失败allow_headers未包含自定义头加入X-Client-Version或设allow_headers=["*"]
Cookie带不过去allow_origins=["*"]allow_credentials=True冲突必须写具体域名,不能*
127.0.0.1vslocalhost浏览器视为不同源两个都加到allow_origins
改了CORS仍报错浏览器缓存了失败的预检清缓存或用无痕窗口使用

三、BackgroundTasks注册后的短信与日志

案例中的需求用户点击立即注册后,主流程进行校验手机号、写入内存数据库、返回201(用户无需等待);后置任务发送欢迎短信、写JSONL审计日志。这些后置任务失败不应影响注册结果,且不应拖慢HTTP响应。
后台任务函数示例:

defsend_sms(phone:str,message:str)->None:importtime time.sleep(0.5)# 模拟同步I/Oprint(f"[SMS]->{phone}:{message}")defwrite_registration_log(user_id:int,phone:str,nickname:str)->None:# 追加写入logs/registrations.jsonl...

注册接口示例:

fromfastapiimportBackgroundTasks@app.post("/api/users/register")asyncdefregister_user(body:UserRegisterRequest,background_tasks:BackgroundTasks):# 校验、保存用户...background_tasks.add_task(send_sms,body.phone,f"欢迎{body.nickname}!")background_tasks.add_task(write_registration_log,user_id,body.phone,body.nickname)returnUserRegisterResponse(user_id=user_id,...)

执行的时序图如下图所示:

四、后台任务与异步任务,别搞混!

概念对照

async/await异步路由BackgroundTasks后台任务
目的在等待I/O时释放事件循环响应返回后执行善后工作
用户是否等待是,必须等路由函数执行完否,响应已先返回
典型场景查数据库、调HTTP API异步客户端发短信、写日志、发邮件
函数类型路由用async def+await任务函数通常是普通 def同步
失败影响直接导致HTTP 5xx不影响已返回的响应

简单的说这次请求还需要等它做完用异步I/O,这次请求已经答完了,顺便帮我把后面的事做了用后台任务。

五、BackgroundTasks与Celery的适用边界

针对后台任务的处理,BackgroundTasksCelery在适用边界上差异显著。前者作为FastAPI内置组件,无需额外依赖,在同一进程的线程池中执行任务,部署简单且启动成本极低,适合低 QPS、短耗时且允许任务丢失的场景如发送通知或记录日志,但它存在明显局限——任务完全驻留内存,进程重启即丢失,不支持延迟执行、定时触发、自动重试,且缺乏有效的监控手段
Celery需引入Redis或RabbitMQ作为消息代理并独立运行Worker进程,部署和维护成本较高,却能提供消息持久化、countdown/eta定时调度、内置重试机制如autoretry_for以及Flower等可视化监控,其独立进程和水平扩展能力使其能够承载高QPS、长耗时且要求可靠交付的生产级任务。因此,开发初期或轻量级需求可优先选用BackgroundTasks以快速迭代,一旦业务对可靠性、延迟容忍度或任务规模提出更高要求,则应果断迁移至Celery,实现架构的平滑演进。
下面提供对比表:

维度BackgroundTasksCelery(+ Redis/RabbitMQ)
部署零依赖,FastAPI内置需Broker、Worker进程
进程模型同一FastAPI进程内线程池独立Worker,可水平扩展
持久化任务在内存,进程重启即丢失消息持久化在队列
延迟/定时不支持支持countdowneta、Crontab
重试需自己写try/except内置autoretry_formax_retries
监控仅 print / 日志Flower、Prometheus 等
适用规模低QPS、短任务、可丢失高QPS、长任务、必须可靠

七、小结

在案例实践中,静态资源通过app.mount("/static", StaticFiles(...))挂载页面所需的CSS、JS及图标;为解决前端5500端口调用后端8000端口服务的跨域问题,利用CORSMiddleware配置中间件,并通过设定allow_headersallow_methodsX-Client-Version等自定义头部触发的OPTIONS预检请求做好应答;对于注册后发短信、写日志等非即时响应任务,则使用BackgroundTasks.add_task()快速实现异步后台执行。
在技术选型上,MVP阶段直接采用轻量的BackgroundTasks即可满足需求,随着业务对可靠性、延迟或大规模任务处理的更高要求,可逐步演进至Celery等专业任务队列,体现按业务阶段渐进式迭代的务实思路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/3 5:21:19

让 TLS 指纹与 UA 一致的抓包分析工具

TLSFOWARD 是一款面向网络调试、指纹检测和浏览器环境分析的抓包软件。它不仅可以实时捕获 HTTP 请求流量,还能查看 TLS 指纹信息,包括 Cipher Suites、Extensions、Signature Algorithms、ALPN、User-Agent 等关键特征,帮助你判断请求环境是…

作者头像 李华
网站建设 2026/7/3 5:19:36

ArkTS 基础语法学习笔记

ArkTS 基础语法学习笔记本文是我学习鸿蒙 ArkTS 基础篇的总结笔记,涵盖基础入门、变量和类型、数组、对象、函数、箭头函数六个部分,方便自己回顾,也希望对同样在学 ArkTS 的朋友有帮助。一、ArkTS 基础入门ArkTS 是华为鸿蒙(Harm…

作者头像 李华
网站建设 2026/7/3 5:19:00

2026智能门锁五大维度硬核实测:安全/识别/猫眼/AI/售后数据对比

2026年千元档(800-1500元)已占线上销量47%,3D人脸、双摄主动防御、五年质保正从高端下放。但配置堆得满不代表体验拉得满——我们选取格行智能门锁、凯迪仕K70、小米智能门锁2 Pro,从安全、识别、猫眼、AI、售后五个维度深度实测。…

作者头像 李华
网站建设 2026/7/3 5:17:19

Java毕设选题推荐:基于 SpringBoot 的垃圾分类宣传与智能监管系统的设计与实现 基于 SpringBoot 的社区垃圾投放记录统计分【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/7/3 5:16:48

AutoGluon实战指南:7行代码冲击Kaggle Top 4%的自动化机器学习全流程

1. 这不是魔法,是AutoGluon把机器学习的“脏活累活”全干了你有没有在Kaggle上盯着Leaderboard发过呆?看着别人的名字排在前5%,自己调了三天XGBoost参数却卡在第37%的位置,连数据清洗都像在解一道没有提示的谜题。我试过——去年参…

作者头像 李华
网站建设 2026/7/3 5:15:03

【全英文期刊收集】

市面最新全英文期刊收集报告 收集日期:2026-07-02 覆盖类别:时事新闻 / 商业财经 / 科技 / 文学文化 / 学术研究 数据来源:各期刊官网及权威媒体榜单 一、时事新闻类(Current Affairs & News) 期刊名称创刊年出版…

作者头像 李华