fastapi官网及详细资料:FastAPI
一、环境搭建实战经验
1. Python 3.11 安装全过程
记得我以前想自己用python写一个网站,然后把家里的老电脑拿出来当服务器,结果还没公网,脚本还一直报错,直到前几天我听朋友介绍了一个云服务器提供商,服务器的问题才解决。
我本来一直用的是python10,但有一个我喜欢的第三方库却只支持11-13,于是我换成了python11.
雨云我觉得很好用,注册连接:雨云 - 老一代云服务提供商_ 用这个链接会便宜很多!
单独优惠码:Mzg2NDk2
记得前几天我第一次在雨云服务器上装Python 3.11,折腾了整整两天。雨云的Ubuntu 22.04默认只带3.10,得自己折腾。下面是我的血泪经验:
# 先更新系统,这个步骤不能省,我试过不更新直接装结果各种依赖问题
sudo apt update
sudo apt upgrade -y
# 安装基础依赖,雨云有些镜像连build-essential都没预装
sudo apt install -y build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libreadline-dev libffi-dev libsqlite3-dev wget libbz2-dev
# 下载Python源码,我习惯用官方地址,虽然雨云有些区域可能慢点
cd /usr/src
sudo wget https://www.python.org/ftp/python/3.11.13/Python-3.11.13.tgz
sudo tar xzf Python-3.11.13.tgz
cd Python-3.11.13
# 这里有个小技巧,雨云服务器内存小的话加--enable-optimizations会编译失败
# 我一般去掉这个参数,虽然性能差一点但至少能装上
sudo ./configure --with-ensurepip=install
sudo make -j$(nproc)
sudo make altinstall
# 验证安装,这个命令我记了好久才记住
python3.11 -V
个人经验: 有次在雨云华东节点装,wget下载特别慢,我就改用国内镜像:
sudo wget https://registry.example.com/python/3.11.13/Python-3.11.13.tgz
结果装完发现pip源也是国内的,后面装包各种问题,最后又得重来。所以还是建议直接用官方源,虽然慢点但稳定。(自处注意,有的雨云服务器不支持从国外下资源,策划前先问一下客服,秒答)
2. 虚拟环境配置技巧
虚拟环境这块我踩过不少坑。雨云服务器上,很多人直接用全局Python,结果多个项目冲突。我的做法:
# 创建项目目录
mkdir -p ~/projects/my_fastapi_app && cd ~/projects/my_fastapi_app
# 创建虚拟环境,我习惯用.venv这个名字,方便gitignore
python3.11 -m venv .venv
# 激活虚拟环境,这个命令我每次都得查,太长了
source .venv/bin/activate
# 安装基础包,我一般先升级pip
pip install --upgrade pip
pip install fastapi uvicorn "python-multipart==0.0.9"
小发现: 有次在雨云服务器上,激活虚拟环境后pip命令找不到,折腾半天发现是PATH没设置好。后来我养成习惯,每次创建虚拟环境后都执行:
echo "source ~/.bashrc" >> .venv/bin/activate
虽然不知道为啥有效,但确实解决了问题。
二、项目结构实战搭建
1. 项目初始化全过程
# 创建标准项目结构
mkdir -p app/{api,core,models,schemas,utils} static/{css,js,img} templates
touch app/{main.py,config.py}
touch app/api/{__init__.py,items.py,users.py}
touch app/core/{__init__.py,config.py}
touch requirements.txt .env
# 填充基础配置
echo "APP_NAME=MyFastAPIApp
DEBUG=True
SECRET_KEY=secret123
DATABASE_URL=sqlite:///./app.db" > .env
echo "fastapi==0.111.0
uvicorn==0.30.6
python-multipart==0.0.9
python-dotenv==1.0.1
sqlalchemy==2.0.30" > requirements.txt
个人习惯: 我喜欢把SECRET_KEY设成"secret123",因为好记。虽然知道应该用复杂点的,但开发环境图个方便嘛。反正上线前再改。
2. 核心配置文件编写
app/core/config.py:
import os
from dotenv import load_dotenv
load_dotenv() # 从.env文件加载环境变量
class Settings:
APP_NAME: str = os.getenv("APP_NAME", "My FastAPI App")
DEBUG: bool = os.getenv("DEBUG", "True") == "True"
SECRET_KEY: str = os.getenv("SECRET_KEY", "secret123")
DATABASE_URL: str = os.getenv("DATABASE_URL", "sqlite:///./app.db")
settings = Settings()
真实经历: 有次在雨云服务器上部署,发现DEBUG设置不生效。查了好久才发现是因为.env
文件权限问题。后来我每次部署都加一句:
chmod 644 .env
虽然不知道为啥需要这个,但确实解决了问题。
三、数据库集成实战
1. SQLAlchemy基础配置
app/core/database.py:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, declarative_base
# 从配置加载数据库URL
from app.core.config import settings
# 创建引擎,雨云RDS连接可以直接用这个
engine = create_engine(
settings.DATABASE_URL,
connect_args={"check_same_thread": False} if "sqlite" in settings.DATABASE_URL else {}
)
# 创建会话工厂
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 基类,所有模型继承这个
Base = declarative_base()
def get_db():
"""获取数据库会话"""
db = SessionLocal()
try:
yield db
finally:
db.close()
实际经验: 有次在雨云上用PostgreSQL,连接老是断。后来发现是雨云RDS有个空闲连接超时设置。我加了个简单的心跳:
from sqlalchemy import event
@event.listens_for(engine, "engine_connect")
def ping_connection(connection, branch):
if branch:
return
try:
connection.scalar("SELECT 1")
except:
connection.rollback()
raise
虽然不太懂原理,但确实让连接稳定多了。
2. 模型定义示例
app/models/user.py:
from sqlalchemy import Column, Integer, String
from app.core.database import Base
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
hashed_password = Column(String)
is_active = Column(Boolean, default=True)
踩坑记录: 有次定义模型时,我用了is_active = Column(Boolean, default=True)
,结果在SQLite上没问题,但部署到雨云RDS的PostgreSQL就报错。最后发现PostgreSQL的Boolean类型需要Boolean(create_constraint=True)
。改了半天才搞定。
四、API路由开发实战
1. 基础API开发
app/api/users.py:
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.models.user import User
from app.schemas.user import UserCreate, UserResponse
router = APIRouter()
@router.post("/", response_model=UserResponse)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
# 检查邮箱是否已存在
db_user = db.query(User).filter(User.email == user.email).first()
if db_user:
raise HTTPException(status_code=400, detail="邮箱已注册")
# 创建新用户
fake_hashed_password = user.password + "notreallyhashed"
db_user = User(email=user.email, hashed_password=fake_hashed_password)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
@router.get("/{user_id}", response_model=UserResponse)
def read_user(user_id: int, db: Session = Depends(get_db)):
db_user = db.query(User).filter(User.id == user_id).first()
if db_user is None:
raise HTTPException(status_code=404, detail="用户不存在")
return db_user
实际经验: 有次在雨云服务器上测试,发现创建用户时密码没加密。查了半天才发现fake_hashed_password
那段代码是测试用的,忘了替换成真正的哈希函数。后来我养成了习惯,在代码里加注释:
# TODO: 替换为真正的密码哈希
fake_hashed_password = user.password + "notreallyhashed"
2. 文件上传功能
app/api/files.py:
import os
from fastapi import APIRouter, UploadFile, File
from fastapi.responses import JSONResponse
router = APIRouter()
@router.post("/upload/")
async def upload_file(file: UploadFile = File(...)):
# 确保uploads目录存在
os.makedirs("uploads", exist_ok=True)
# 保存文件
file_path = f"uploads/{file.filename}"
with open(file_path, "wb") as buffer:
buffer.write(await file.read())
return {"filename": file.filename, "path": file_path}
真实故事: 有次在雨云上部署这个功能,用户上传了中文名文件,结果乱码。我试了各种编码转换都不行,最后发现是服务器locale设置问题。执行了:
sudo locale-gen zh_CN.UTF-8
sudo update-locale LANG=zh_CN.UTF-8
重启服务器后才解决。雨云有些基础镜像默认是en_US,处理中文文件要注意。
五、生产环境部署深度指南
1. Gunicorn配置实战
gunicorn_conf.py:
# Gunicorn配置文件
bind = "127.0.0.1:8000"
workers = 3 # 一般设为CPU核心数+1
worker_class = "uvicorn.workers.UvicornWorker"
timeout = 120
keepalive = 5
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
errorlog = "-"
accesslog = "-"
loglevel = "info"
个人经验: 有次在雨云2核4G服务器上,我把workers设成5,结果内存不够用,经常OOM。后来发现公式应该是:
workers = (2 * CPU核心数) + 1
但雨云有些小配置服务器内存有限,得适当减少。我一般先设小点,运行几天看监控再调整。
2. Systemd服务配置
# 创建服务目录
sudo mkdir -p /var/log/gunicorn
# 创建服务文件
sudo nano /etc/systemd/system/fastapi.service
/etc/systemd/system/fastapi.service:
[Unit]
Description=FastAPI Service
After=network.target
[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=/home/ubuntu/projects/my_fastapi_app
Environment="PATH=/home/ubuntu/projects/my_fastapi_app/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
EnvironmentFile=/home/ubuntu/projects/my_fastapi_app/.env
ExecStart=/home/ubuntu/projects/my_fastapi_app/.venv/bin/gunicorn -c gunicorn_conf.py app.main:app
Restart=always
RestartSec=5
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=fastapi
[Install]
WantedBy=multi-user.target
血泪教训: 有次配置完服务,启动时报错Failed at step EXEC spawning
. 查了好久发现是.env
文件里有空格,比如:
SECRET_KEY = mysecret
改成:
SECRET_KEY=mysecret
就好了。环境变量等号两边不能有空格,这个细节坑了我好几次。
3. Nginx配置实战
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/my_fastapi
/etc/nginx/sites-available/my_fastapi:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static {
alias /home/ubuntu/projects/my_fastapi_app/static;
}
}
启用站点:
sudo ln -s /etc/nginx/sites-available/my_fastapi /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
真实案例: 有次配置完Nginx,访问网站显示502 Bad Gateway。查了好久才发现是Gunicorn没启动。雨云服务器有时候需要先启动应用再配Nginx。我后来养成了习惯:
- 先用
uvicorn app.main:app --reload
测试应用 - 确认能访问后再配Nginx
- 最后用Gunicorn替换Uvicorn
六、雨云服务器部署全流程
1. 雨云服务器选购指南
我一般在雨云买服务器,有几个小技巧分享:
- 地域选择:如果你的用户主要在国内,选浙江宁波或广东广州(极为推荐,阿里腾讯支持,高防DDOS)区域,延迟更低
- 配置选择:新手建议2核4G起步,2核2G太卡,开发体验差(亲身体验,4G比2G只多7元)
- 系统选择:Ubuntu 22.04 LTS最稳定,CentOS 7也行但快EOL了
- 带宽选择:30Mbps够测试用,正式环境至少50Mbps
个人经历: 有次为了省钱买了1核1G的雨云服务器,结果连Python都装不上,提示内存不足。后来才知道编译Python需要至少1.5G内存。所以现在我都直接买2核4G。(只要30多块,一天1块钱)
2. 雨云服务器初始化步骤
连接服务器:
# 雨云控制台会提供root密码
ssh root@your-rainyun-server-ip
基础配置:
# 创建普通用户(雨云默认只有root)
adduser deploy
usermod -aG sudo deploy
# 切换到普通用户
su - deploy
# 安装基础工具
sudo apt update
sudo apt install -y git curl wget vim
雨云特色: 雨云控制台有个"自定义脚本"功能,可以在创建服务器时自动执行脚本。我经常用这个预装基础环境:
#!/bin/bash
apt update
apt install -y python3.11 python3.11-venv git nginx
3. 雨云安全组配置
雨云的安全组设置很关键,但新手容易配错。我的配置:
- 入站规则:
- SSH (22/tcp) - 仅限自己IP
- HTTP (80/tcp) - 0.0.0.0/0
- HTTPS (443/tcp) - 0.0.0.0/0
- 出站规则:
- 全部允许
踩坑记录: 有次配置完安全组,还是无法访问网站。查了好久才发现是雨云安全组需要"应用"才能生效,不是保存就生效。这个细节雨云文档没写清楚。
4. 雨云备份策略
雨云有自动备份功能,但我觉得不够用。我的备份方案:
- 代码备份:用Git,推送到GitHub或Gitee
- 数据库备份:每天定时导出
0 2 * * * pg_dump -U user dbname > /backups/db_$(date +\%Y\%m\%d).sql
- 完整备份:每周用雨云快照功能
真实故事: 有次误删了数据库,以为雨云自动备份能救我。结果发现自动备份只保留7天,而我的问题是3周前埋下的。从此我加了邮件通知,确保备份成功。
七、高级技巧与个人经验
1. 雨云服务器性能优化
交换空间设置:
# 雨云小内存服务器必备
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 永久生效
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
为什么需要: 有次在雨云1核2G服务器上,Python编译时内存不够,加了2G交换空间才成功。虽然慢点,但至少能用。
2. 日志管理技巧
集中日志配置:
# 安装日志轮转
sudo apt install -y logrotate
# 创建配置
sudo nano /etc/logrotate.d/fastapi
/etc/logrotate.d/fastapi:
/var/log/gunicorn/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 ubuntu ubuntu
sharedscripts
postrotate
systemctl reload fastapi > /dev/null
endscript
}
个人经验: 有次日志文件涨到10G,把雨云服务器磁盘撑满了。从此我养成了定期清理日志的习惯,还加了监控告警。
3. 雨云监控实用技巧
雨云自带监控功能有限,我加了些自定义监控:
CPU监控脚本:
#!/bin/bash
# /usr/local/bin/cpu_monitor.sh
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
if (( $(echo "$CPU_USAGE > 90" | bc -l) )); then
echo "CPU usage is high: $CPU_USAGE%" | mail -s "CPU Alert" your@email.com
fi
添加到crontab:
*/5 * * * * /usr/local/bin/cpu_monitor.sh
真实案例: 有次API突然变慢,雨云监控显示CPU正常,但实际是某个worker卡住了。后来我加了应用级监控,看每个请求的响应时间。
八、常见问题解决方案大全
1. Python环境问题
问题:ModuleNotFoundError: No module named 'fastapi'
- 现象:明明装了fastapi,但运行时报错
- 原因:虚拟环境没激活,或用了系统Python
- 解决方案:
# 确认当前Python路径 which python # 如果不对,重新激活虚拟环境 source .venv/bin/activate # 或者直接指定Python路径 /path/to/.venv/bin/python app/main.py
个人经历: 有次在雨云服务器上,which python
显示的是系统Python,但python --version
显示虚拟环境的。查了好久才发现PATH设置有问题,把虚拟环境路径加到了.bashrc里。
2. 端口冲突问题
问题:OSError: [Errno 98] Address already in use
- 现象:启动应用时端口被占用
- 原因:之前进程没完全退出
- 解决方案:
# 查找占用8000端口的进程 sudo lsof -i :8000 # 或者 sudo ss -tulpn | grep :8000 # 终止进程 kill -9 <PID> # 一键解决 sudo fuser -k 8000/tcp
小技巧: 我在开发时经常用这个别名,加到~/.bashrc:
alias killport='sudo fuser -k $1/tcp'
然后就可以killport 8000
快速杀进程。
3. 数据库连接问题
问题:sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file
- 现象:SQLite数据库打不开
- 原因:目录不存在或权限不足
- 解决方案:
# 确保目录存在 mkdir -p $(dirname ./app.db) # 设置正确权限 chmod 755 $(dirname ./app.db) chmod 644 ./app.db # 如果还是不行,用绝对路径 DATABASE_URL=sqlite:////absolute/path/to/app.db
真实案例: 有次在雨云服务器上,SQLite文件放在/tmp目录,结果服务器重启后文件没了。从此我再也不把数据库放/tmp了。
4. Nginx配置问题
问题:502 Bad Gateway
- 现象:Nginx显示502错误
- 原因:后端应用没启动或端口不对
- 排查步骤:
- 检查应用是否运行:
systemctl status fastapi
- 检查端口监听:
ss -tulpn | grep 8000
- 测试本地访问:
curl http://127.0.0.1:8000
- 查看Nginx错误日志:
tail -f /var/log/nginx/error.log
- 检查应用是否运行:
个人经验: 有次502错误是因为Gunicorn worker超时,我加了--timeout 120
参数就解决了。雨云有些小配置服务器处理慢请求容易超时。
5. 静态文件问题
问题:CSS/JS文件404
- 现象:页面样式丢失
- 原因:Nginx没正确配置静态文件路径
- 解决方案:
注意:location /static { alias /path/to/your/static/files; expires 30d; }
alias
和root
的区别,用错会导致路径问题
血泪教训: 有次我把alias
写成root
,结果静态文件路径变成了/static/static/css/style.css
。调试了好久才发现这个小错误。
九、雨云特色功能实战
1. 雨云对象存储集成
雨云有对象存储服务,我用来存用户上传的文件:
# app/utils/storage.py
import os
import requests
from app.core.config import settings
def upload_to_rainyun_oss(file_path, object_name=None):
"""上传文件到雨云OSS"""
if object_name is None:
object_name = os.path.basename(file_path)
# 雨云OSS API端点
url = f"https://{settings.OSS_BUCKET}.{settings.OSS_REGION}.rainyun-oss.com/{object_name}"
# 读取文件
with open(file_path, 'rb') as f:
file_data = f.read()
# 上传(这里简化了,实际需要签名)
headers = {
"Authorization": f"Bearer {settings.OSS_ACCESS_KEY}"
}
response = requests.put(url, data=file_data, headers=headers)
return response.status_code == 200
配置: 在.env
文件中添加:
OSS_BUCKET=my-bucket
OSS_REGION=cn-east
OSS_ACCESS_KEY=your-access-key
OSS_SECRET_KEY=your-secret-key
真实经历: 有次上传大文件超时,后来发现雨云OSS默认超时是60秒。我改用分片上传才解决。
2. 雨云监控告警配置
雨云自带监控可以设告警,但不够灵活。我加了个脚本:
#!/bin/bash
# /usr/local/bin/rainyun_monitor.sh
# 检查服务状态
if ! systemctl is-active --quiet fastapi; then
echo "FastAPI服务已停止!" | mail -s "服务告警" your@email.com
systemctl start fastapi
fi
# 检查磁盘空间
if [ $(df / | tail -1 | awk '{print $5}' | sed 's/%//') -gt 90 ]; then
echo "磁盘空间不足!" | mail -s "磁盘告警" your@email.com
fi
添加到crontab:
*/10 * * * * /usr/local/bin/rainyun_monitor.sh
个人经验: 有次雨云服务器磁盘满了,监控邮件没收到,因为邮件服务也挂了。现在我会把告警发到多个渠道,比如企业微信。
十、实战经验总结
1. 部署流程优化
我总结了一套雨云部署checklist,每次部署都按这个来:
服务器准备
- 确认雨云安全组开放必要端口
- 创建普通用户,配置SSH密钥
- 安装基础工具(git, curl, vim)
环境配置
- 安装Python 3.11
- 创建虚拟环境
- 安装依赖包
应用部署
- 克隆代码库
- 配置环境变量
- 初始化数据库
服务配置
- 设置Gunicorn
- 配置Nginx
- 启用systemd服务
验证测试
- 检查服务状态
- 测试API端点
- 验证静态文件
小技巧: 我把整个流程写成脚本,命名为deploy.sh
,每次部署只需运行:
./deploy.sh production
2. 个人踩坑记录
坑1:雨云服务器时区问题
- 现象:日志时间与本地不一致
- 解决:设置正确时区
sudo timedatectl set-timezone Asia/Shanghai
坑2:SQLite在雨云上性能差
- 现象:高并发时数据库锁住
- 解决:换用PostgreSQL,雨云有RDS服务
坑3:雨云自动更新内核
- 现象:某天服务突然变慢
- 解决:禁用自动更新
sudo apt-mark hold linux-image-generic
3. 给新手的建议
- 不要怕犯错:我第一次在雨云部署失败了4次,每次都是小问题
- 做好备份:雨云快照功能很实用,部署前先拍个快照
- 从小配置开始:新手别买太贵的服务器,2核4G足够学习
- 善用日志:出问题先看日志,
journalctl -u fastapi -f
是我的救命稻草 - 保持耐心:云计算有学习曲线,慢慢来
4. 最后的真心话
说实话,这个教程写得有点乱,因为真实开发就是这样——没有完美的流程,只有不断试错和调整。我在雨云上部署过不下4个FastAPI项目,每个都有不同的问题。
记得有次上线前夜,发现生产环境和开发环境行为不一致,折腾到凌晨4点才发现是.env
文件里有个空格。从此我养成了用env | sort
对比环境变量的习惯。
雨云是个不错的平台,但别指望它解决所有问题。云计算的本质是:你省了买硬件的钱,但得多花时间学运维。希望这篇实战经验能帮你少踩几个坑。
最后提醒:代码里的SECRET_KEY=secret123
只是示例,实际项目一定要改!我见过太多人直接用这个上线,结果...你懂的。(被hack...)
补充链接:雨云 - 老一代云服务提供商_ 直降5折。