
1. 从零到一为什么选择Flask作为你的第一个Web后端如果你刚接触Python想自己动手做个网站或者想给数据分析脚本加个能通过浏览器访问的界面那你大概率会听到一个名字Flask。网上教程铺天盖地但很多一上来就是from flask import Flask然后让你照抄代码却很少告诉你为什么在Django、FastAPI这些框架里偏偏是Flask最适合新手入门。我自己带过不少新人项目也踩过从“Hello World”到生产部署的所有坑今天就来聊聊怎么用Flask这个“微框架”实实在在地写出一个能用的网页后端而不仅仅是跑通一个Demo。Flask的核心优势就两个字灵活。它不像Django那样给你预设好数据库ORM、用户认证、后台管理等一系列“全家桶”。Flask只提供最核心的路由、请求响应和模板渲染其他功能你需要什么再用扩展Extension像搭积木一样装上去。这种“按需取用”的模式对初学者来说最大的好处是学习路径清晰。你不用一开始就被Django庞大的项目结构和抽象概念吓住而是能清晰地看到一个URL请求是怎么进来经过你的代码处理再变成HTML页面或JSON数据发回去的。这个“请求-响应”的闭环是理解Web开发最根本的模型。举个例子很多新手想做个简单的数据查询页面。用Flask你可能只需要30行代码10行连接数据库10行写查询逻辑10行用Jinja2模板把数据塞进HTML。整个过程直观明了。如果你一开始就用一个重型框架光搞懂项目目录里十几个文件夹是干嘛的可能就得花上半天。所以当你搜索“python 做网页 后端 入门”时Flask总被推荐不是因为它最强而是因为它能让你最快地获得“我做出了一个能访问的网页”的正反馈这是坚持学习的关键。2. 环境搭建与项目初始化避开第一个坑万事开头难而Web开发的开头往往卡在环境配置上。很多人照着教程pip install flask一气呵成但一到实际写项目就遇到包冲突、路径不对、虚拟环境没激活等问题。下面我以一个真实的个人博客后端项目为例带你走一遍最稳妥的初始化流程。2.1 虚拟环境项目的“隔离舱”这是你必须养成的第一个好习惯。永远不要在系统的全局Python环境里直接安装项目依赖。想象一下你系统里原来有个项目用Flask 1.0新项目需要Flask 2.0直接安装就会覆盖可能导致旧项目跑不起来。虚拟环境就是为每个项目创建一个独立的Python运行环境。我推荐使用venv它是Python 3.3自带的无需额外安装。# 1. 创建一个项目目录并进入 mkdir my_flask_blog cd my_flask_blog # 2. 创建虚拟环境。这里的 venv 是虚拟环境文件夹的名字通常就叫venv python -m venv venv # 3. 激活虚拟环境 # 在 Windows 上 venv\Scripts\activate # 在 macOS/Linux 上 source venv/bin/activate激活后你的命令行提示符前面通常会显示(venv)表示你已经在这个“隔离舱”里了。之后所有pip install的操作都只影响这个环境。2.2 依赖管理用requirements.txt固化环境项目依赖不应该靠人脑记忆。安装完Flask后第一时间生成依赖清单。# 安装Flask核心包 pip install flask # 将当前环境的所有包及其版本号导出到 requirements.txt 文件 pip freeze requirements.txt现在你的项目根目录下会有一个requirements.txt文件里面大概有一行Flask2.3.3版本号可能不同。这个文件要纳入版本控制如Git。当你的队友或者在另一台电脑上需要运行这个项目时他只需要克隆代码。创建并激活虚拟环境。执行pip install -r requirements.txt。所有依赖都会自动安装到正确的版本完美复现你的开发环境。这是团队协作和项目部署的基石。2.3 项目结构迈出规范的第一步一个清晰的目录结构能让你的思路更清晰。对于刚起步的Flask项目我建议采用如下结构它足够简单又为后续扩展留有余地my_flask_blog/ ├── venv/ # 虚拟环境目录.gitignore忽略掉 ├── app.py # 应用主入口文件 ├── requirements.txt # 依赖清单 ├── static/ # 存放静态文件CSS, JavaScript, 图片 │ ├── css/ │ ├── js/ │ └── images/ └── templates/ # 存放Jinja2 HTML模板文件 └── index.html先通过命令行创建好static和templates文件夹。这个结构符合Flask的默认约定当你写代码引用静态文件或渲染模板时Flask会自动在这些文件夹里查找。注意venv文件夹绝对不能提交到Git。务必在项目根目录创建一个名为.gitignore的文件里面加上一行venv/。你也可以直接去GitHub官方的gitignore模板库找一个Python模板来用它会帮你忽略更多不必要的文件比如__pycache__/、.pyc文件等。3. 核心三要素路由、视图与模板环境搭好我们来解剖Flask最核心的三个概念。理解了它们你就掌握了Flask大半的功力。3.1 路由与视图函数URL的指挥家在Flask中路由Route的作用是把一个URL地址绑定到一个Python函数上。这个函数就叫视图函数View Function。当用户访问那个URL时对应的视图函数就会被执行它的返回值就是给用户的响应。打开app.py写下你的第一个Flask应用from flask import Flask app Flask(__name__) # 创建Flask应用实例__name__用于确定资源路径 app.route(/) # 路由装饰器将根URL / 绑定到下面的函数 def hello_world(): return Hello, World! 这是我的第一个Flask网页。 app.route(/about) def about(): return h1关于我/h1p这是一个用Flask搭建的博客。/p if __name__ __main__: app.run(debugTrue) # 启动开发服务器debugTrue开启调试模式运行python app.py访问http://127.0.0.1:5000/和http://127.0.0.1:5000/about你会看到不同的内容。app.route(‘/’)这个语法叫装饰器它“装饰”了下面的函数告诉Flask“当用户访问网站根目录时就执行hello_world这个函数。”视图函数可以返回字符串Flask会把它包装成HTTP响应发回给浏览器。返回的字符串如果包含HTML标签如h1浏览器就会将其渲染。但这只是开始。网站需要动态内容比如根据文章ID显示不同文章。这就需要动态路由。app.route(/article/int:article_id) # int:article_id 定义了一个动态片段并转换为整数类型 def show_article(article_id): # 理论上这里你会用 article_id 去数据库查询文章 return f你正在查看文章 #{article_id} 的内容。 app.route(/user/username) def show_user_profile(username): return f用户 {username} 的主页。int:article_id是一个转换器它从URL中捕获值并转换成指定的类型这里是整数然后作为参数传递给视图函数。Flask内置了string、int、float、path等多种转换器。3.2 模板渲染告别在代码里拼接HTML在视图函数里用f-string或者字符串拼接来生成HTML对于复杂页面来说是场灾难。代码又乱又难维护前端和后端逻辑完全搅在一起。Flask使用Jinja2模板引擎来解决这个问题。模板就是一个包含特殊占位符的HTML文件。我们在Python代码里准备好数据称为“上下文”然后交给Jinja2去填充模板生成最终的HTML。首先在templates目录下创建index.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 title{{ site_title }} - 我的Flask博客/title !-- 双大括号是变量占位符 -- link relstylesheet href{{ url_for(static, filenamecss/style.css) }} /head body h1{{ welcome_message }}/h1 ul !-- 这是Jinja2的控制结构用于循环 -- {% for post in posts %} li a href/article/{{ post.id }}{{ post.title }}/a span发布于{{ post.date }}/span /li {% endfor %} /ul !-- 使用url_for动态生成静态文件或视图的URL是Flask最佳实践 -- img src{{ url_for(static, filenameimages/logo.png) }} altLogo /body /html然后修改app.py中的视图函数使用render_template来渲染它from flask import Flask, render_template from datetime import datetime app Flask(__name__) app.route(/) def index(): # 准备要传递给模板的数据 context { site_title: 首页, welcome_message: 欢迎来到我的技术博客, posts: [ {id: 1, title: Flask入门指南, date: datetime(2023, 10, 27)}, {id: 2, title: Python数据分析实战, date: datetime(2023, 10, 26)}, {id: 3, title: SQLAlchemy ORM详解, date: datetime(2023, 10, 25)}, ] } # 渲染模板第二个参数开始是模板变量 return render_template(index.html, **context) # **context 将字典解包成关键字参数关键点解析{{ ... }}用于输出变量或表达式的结果。{% ... %}用于执行控制逻辑如循环{% for ... %}、条件判断{% if ... %}。url_for(‘static’, filename‘...’)这是Flask提供的函数用于安全、可靠地生成静态文件的URL。即使你以后修改了URL结构这里也无需改动。对于视图函数也可以用url_for(‘show_article’, article_id1)来生成/article/1这个链接这是解耦的体现。render_templateFlask会在templates文件夹下自动查找指定的模板文件。3.3 处理请求数据GET与POSTWeb应用离不开交互。用户通过表单提交数据登录、搜索、评论后端需要接收并处理。这主要涉及两种HTTP方法GET和POST。GET参数附在URL之后如/search?qflask用于获取数据不应改变服务器状态。参数通过request.args获取。POST参数放在请求体Body中用于提交数据可能改变服务器状态如新增文章。参数通过request.form获取。我们创建一个简单的登录页来演示首先创建templates/login.htmlform methodPOST action{{ url_for(login) }} label用户名/label input typetext nameusername requiredbr label密码/label input typepassword namepassword requiredbr button typesubmit登录/button /form p{{ message }}/p !-- 用于显示登录成功或失败的消息 --然后在app.py中添加处理逻辑from flask import Flask, render_template, request, redirect, url_for app Flask(__name__) # 显示登录表单的页面GET请求 app.route(/login, methods[GET]) def login_form(): return render_template(login.html, message请登录) # 处理登录表单提交POST请求 app.route(/login, methods[POST]) def login(): # 从POST请求的表单中获取数据 username request.form.get(username) password request.form.get(password) # 这里应该是复杂的验证逻辑比如查数据库 # 此处简化为硬编码验证 if username admin and password 123456: # 验证成功重定向到首页 return redirect(url_for(index)) else: # 验证失败返回登录页并提示错误 return render_template(login.html, message用户名或密码错误)核心要点路由的methods参数同一个URL/login可以绑定多个视图函数通过指定不同的HTTP方法[‘GET’]和[‘POST’]来区分。这是RESTful风格的常见做法。request对象它封装了当前HTTP请求的所有信息。request.form是一个类似字典的对象存储了POST请求提交的表单数据。request.args存储GET请求的URL参数。重定向redirect(url_for(‘index’))。用户登录成功后我们不应该直接返回一个HTML页面虽然可以而是应该告诉浏览器“请去访问另一个地址首页”。这能防止用户刷新页面时重复提交表单是Web开发的标准实践。安全性示例中的密码验证是极不安全的。真实项目中密码必须加盐哈希存储如使用werkzeug.security中的generate_password_hash和check_password_hash并且要防范SQL注入、XSS等攻击。直接拼接SQL查询是绝对禁止的。4. 连接数据库让数据持久化一个没有数据库的博客就像一本每次刷新都会清空内容的笔记本。我们需要把文章、用户信息存起来。Python生态里操作关系型数据库如MySQL、PostgreSQL、SQLite最主流的方式是ORM对象关系映射。它允许你用Python类和对象来操作数据库表无需写复杂的SQL语句。对于Flask首推的ORM是Flask-SQLAlchemy它是SQLAlchemy的Flask集成版。4.1 安装与配置首先安装扩展pip install flask-sqlalchemy pymysql这里同时安装了pymysql因为我们将以MySQL为例。如果你用SQLite则不需要。在app.py中配置数据库连接from flask import Flask from flask_sqlalchemy import SQLAlchemy import os app Flask(__name__) # 配置数据库连接URI # 格式数据库类型://用户名:密码服务器地址/数据库名?参数 app.config[SQLALCHEMY_DATABASE_URI] mysqlpymysql://root:your_passwordlocalhost:3306/my_flask_blog?charsetutf8mb4 # 如果你用SQLite路径可以是相对或绝对路径 # app.config[SQLALCHEMY_DATABASE_URI] sqlite:/// os.path.join(app.root_path, data.db) app.config[SQLALCHEMY_TRACK_MODIFICATIONS] False # 关闭对模型修改的跟踪节省内存 db SQLAlchemy(app) # 初始化SQLAlchemy绑定到app配置详解SQLALCHEMY_DATABASE_URI最重要的配置。mysqlpymysql表示使用MySQL数据库并用pymysql作为驱动。localhost:3306是数据库服务器地址和端口。my_flask_blog是你要连接的数据库名需要提前在MySQL中创建好。charsetutf8mb4确保支持完整的UTF-8字符如Emoji。SQLALCHEMY_TRACK_MODIFICATIONS设置为False以避免不必要的性能开销和警告。4.2 定义数据模型模型Model是Python类它对应数据库中的一张表。类的属性对应表的列。# 在app.py中定义模型 class User(db.Model): 用户模型 id db.Column(db.Integer, primary_keyTrue) # 主键 username db.Column(db.String(80), uniqueTrue, nullableFalse) # 用户名唯一且非空 email db.Column(db.String(120), uniqueTrue, nullableFalse) # 建立一对多关系一个用户有多篇文章。backref会在Article模型中创建一个author属性用于反向引用。 posts db.relationship(Article, backrefauthor, lazyTrue) def __repr__(self): return fUser {self.username} class Article(db.Model): 文章模型 id db.Column(db.Integer, primary_keyTrue) title db.Column(db.String(200), nullableFalse) content db.Column(db.Text, nullableFalse) # Text类型用于长文本 create_time db.Column(db.DateTime, defaultdatetime.utcnow) # 默认值为当前UTC时间 # 外键关联到User表的id列。ondeleteCASCADE表示用户删除时其文章也级联删除。 user_id db.Column(db.Integer, db.ForeignKey(user.id, ondeleteCASCADE), nullableFalse) def __repr__(self): return fArticle {self.title}字段类型与参数db.Integer,db.String,db.Text,db.DateTime定义列的数据类型。primary_keyTrue设为主键。uniqueTrue值必须唯一。nullableFalse不允许为空NOT NULL。default...设置默认值。db.ForeignKey(‘表名.列名’)定义外键关系。4.3 创建数据库表与基本操作定义好模型后需要在Python交互环境中创建对应的表。我们可以在项目根目录创建一个简单的脚本init_db.pyfrom app import app, db with app.app_context(): # Flask应用上下文确保操作在应用环境中进行 db.create_all() # 根据模型创建所有表 print(数据库表创建成功)运行python init_db.pyFlask-SQLAlchemy会根据你的模型在配置的数据库中生成user和article表如果不存在。现在我们可以在视图函数中使用这些模型进行增删改查CRUDapp.route(/add_article, methods[POST]) def add_article(): title request.form.get(title) content request.form.get(content) # 假设当前登录用户的id是1真实场景中应从session获取 user_id 1 if title and content: # 创建Create新文章对象 new_article Article(titletitle, contentcontent, user_iduser_id) db.session.add(new_article) # 将对象添加到会话 db.session.commit() # 提交会话将更改保存到数据库 return redirect(url_for(index)) return 标题和内容不能为空 app.route(/article/int:article_id) def show_article(article_id): # 查询Read单篇文章 article Article.query.get_or_404(article_id) # 如果没找到返回404页面 return render_template(article_detail.html, articlearticle) app.route(/articles) def list_articles(): # 查询Read所有文章按创建时间倒序排列 articles Article.query.order_by(Article.create_time.desc()).all() return render_template(article_list.html, articlesarticles) # 更新Update和删除Delete操作类似 # update: article Article.query.get(id); article.title ‘新标题’; db.session.commit() # delete: article Article.query.get(id); db.session.delete(article); db.session.commit()核心操作解析db.session可以把它看作一个数据库事务的“暂存区”。所有的增删改操作都需要先add到这个session最后再commit才会真正写入数据库。这保证了操作的原子性。Article.query这是Flask-SQLAlchemy提供的查询接口非常强大。.get()通过主键查询.filter_by()或.filter()进行条件过滤.order_by()排序.all()获取所有结果列表.first()获取第一个结果。get_or_404()一个便捷方法查询不到时自动返回404错误响应避免手动判断。实操心得数据库操作一定要放在try...except块中并对db.session.commit()可能抛出的异常进行回滚db.session.rollback()。例如用户名重复uniqueTrue会导致提交失败。此外在生产环境中连接池配置、慢查询监控等都是必须考虑的。5. 蓝图与项目结构优化从小作坊到模块化当你的应用功能越来越多把所有路由和视图函数都写在app.py里这个文件很快就会变得臃肿不堪难以维护。这时你需要蓝图Blueprint。蓝图是Flask用来组织应用模块化的工具你可以把相关的路由比如用户认证、博客文章、后台管理分组到不同的蓝图中让项目结构清晰明了。5.1 使用蓝图重构项目假设我们要把博客功能拆分成auth认证、blog博客、admin管理三个模块。首先调整项目结构my_flask_blog/ ├── venv/ ├── requirements.txt ├── app.py # 应用工厂和主入口 ├── config.py # 配置文件 ├── extensions.py # 扩展初始化如db ├── blueprints/ │ ├── __init__.py │ ├── auth.py # 认证蓝图 │ ├── blog.py # 博客蓝图 │ └── admin.py # 管理蓝图 ├── models.py # 集中定义所有数据模型 ├── static/ └── templates/ ├── auth/ ├── blog/ └── admin/关键文件内容config.py集中管理配置方便区分开发、测试、生产环境。import os basedir os.path.abspath(os.path.dirname(__file__)) class Config: SECRET_KEY os.environ.get(SECRET_KEY) or a-hard-to-guess-string # 用于加密会话等 SQLALCHEMY_DATABASE_URI os.environ.get(DATABASE_URL) or \ sqlite:/// os.path.join(basedir, data.db) SQLALCHEMY_TRACK_MODIFICATIONS Falseextensions.py初始化扩展避免循环导入。from flask_sqlalchemy import SQLAlchemy db SQLAlchemy() # 先创建扩展对象但不绑定appmodels.py定义模型从extensions导入db。from extensions import db from datetime import datetime class User(db.Model): # ... 同上 ... class Article(db.Model): # ... 同上 ...blueprints/blog.py创建一个博客蓝图。from flask import Blueprint, render_template from models import Article # 创建一个名为‘blog’的蓝图并指定其模板文件夹可选 bp Blueprint(blog, __name__, url_prefix/blog) # url_prefix会给该蓝图下所有路由加上‘/blog’前缀 bp.route(/) def index(): articles Article.query.order_by(Article.create_time.desc()).all() return render_template(blog/index.html, articlesarticles) bp.route(/int:article_id) def detail(article_id): article Article.query.get_or_404(article_id) return render_template(blog/detail.html, articlearticle)app.py应用工厂模式。from flask import Flask from config import Config from extensions import db from blueprints.auth import bp as auth_bp from blueprints.blog import bp as blog_bp from blueprints.admin import bp as admin_bp def create_app(config_classConfig): app Flask(__name__) app.config.from_object(config_class) # 加载配置 # 初始化扩展 db.init_app(app) # 注册蓝图 app.register_blueprint(auth_bp) app.register_blueprint(blog_bp) app.register_blueprint(admin_bp) return app # 创建应用实例 app create_app() if __name__ __main__: app.run(debugTrue)这样做的好处解耦每个功能模块独立便于多人协作开发。可维护性代码按功能组织查找和修改非常方便。可复用性蓝图可以轻松地在不同项目间迁移。灵活性可以为不同蓝图设置不同的URL前缀、静态文件夹或模板文件夹。5.2 处理静态文件与模板在蓝图中如果你有该模块专用的静态文件如CSS/JS或模板可以在创建蓝图时指定bp Blueprint(admin, __name__, url_prefix/admin, static_folderstatic/admin, # 蓝图专用静态文件夹 template_foldertemplates/admin) # 蓝图专用模板文件夹这样在admin蓝图下的视图函数中使用render_template(‘some_page.html’)时Flask会优先在templates/admin/目录下查找。对于项目共用的静态文件如全局CSS、JS库仍然放在项目根目录的static文件夹下在模板中通过url_for(‘static’, filename‘...’)引用。6. 用户认证与会话管理实现登录与登出一个完整的Web应用几乎都需要用户系统。Flask提供了session对象和flask-login扩展来简化认证流程。6.1 使用Flask-Login管理用户状态首先安装pip install flask-login在extensions.py中初始化from flask_login import LoginManager login_manager LoginManager() login_manager.login_view auth.login # 指定未登录用户访问受保护页面的跳转地址 login_manager.login_message 请先登录。在models.py的User模型中必须实现几个Flask-Login要求的方法from extensions import db, login_manager from flask_login import UserMixin # 一个混入类提供了默认实现 class User(UserMixin, db.Model): # 多重继承UserMixin id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(80), uniqueTrue, nullableFalse) password_hash db.Column(db.String(128)) # 存储哈希后的密码而非明文 # ... 其他字段 ... # UserMixin已经提供了以下方法的默认实现通常无需重写 # is_authenticated, is_active, is_anonymous, get_id # 但如果你有特殊需求如封禁用户可以重写它们。 # 这个回调函数用于根据存储在session中的用户ID重新加载用户对象 login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id))在blueprints/auth.py中实现登录登出逻辑from flask import Blueprint, render_template, redirect, url_for, flash, request from flask_login import login_user, logout_user, login_required, current_user from werkzeug.security import check_password_hash from models import User bp Blueprint(auth, __name__, url_prefix/auth) bp.route(/login, methods[GET, POST]) def login(): if request.method POST: username request.form.get(username) password request.form.get(password) user User.query.filter_by(usernameusername).first() # 验证用户存在且密码正确 if user and check_password_hash(user.password_hash, password): login_user(user) # 关键将用户登录状态存入session flash(登录成功, success) next_page request.args.get(next) # 获取之前尝试访问的页面 return redirect(next_page or url_for(blog.index)) # 跳转 else: flash(用户名或密码错误。, danger) return render_template(auth/login.html) bp.route(/logout) login_required # 装饰器保护该路由只有登录用户才能访问 def logout(): logout_user() # 清除session中的用户信息 flash(你已成功登出。, info) return redirect(url_for(blog.index))关键点login_user(user)这是核心。它会在用户的浏览器中设置一个加密的Cookiesession其中包含了用户的ID。login_required这个装饰器放在任何需要登录才能访问的视图函数上。如果未登录用户访问会被重定向到login_manager.login_view指定的页面即auth.login。current_user在视图函数和模板中你可以直接使用这个代理对象来访问当前登录的用户。如果用户未登录current_user是一个匿名用户对象is_authenticated属性为False。flash()用于在页面间传递一次性消息如“登录成功”需要在模板中通过get_flashed_messages()获取并显示。6.2 密码安全哈希与加盐永远不要明文存储密码使用werkzeug.securityFlask自带来安全地处理密码。from werkzeug.security import generate_password_hash, check_password_hash # 在创建用户或修改密码时 hashed_pw generate_password_hash(my_plaintext_password) # 将 hashed_pw 存入数据库的 password_hash 字段 # 在验证密码时 # user.password_hash 是从数据库取出的哈希值 is_correct check_password_hash(user.password_hash, input_password)generate_password_hash会自动生成一个随机的“盐”salt并将其与密码一起哈希。即使两个用户密码相同其哈希值也不同这极大地增强了安全性。7. 部署上线从开发服务器到生产环境在本地用app.run(debugTrue)跑起来的服务器Werkzeug是仅供开发使用的性能差且不安全。要真正让网站能被公网访问你需要一个生产级的WSGI服务器并搭配一个反向代理如Nginx。7.1 使用Gunicorn作为WSGI服务器Gunicorn是一个纯Python的WSGI HTTP服务器性能远强于开发服务器。首先安装pip install gunicorn创建一个简单的启动脚本wsgi.py在项目根目录from app import app if __name__ __main__: app.run()然后在生产环境的服务器上假设你已通过Git拉取了代码并配置好虚拟环境使用Gunicorn启动应用# 基本启动监听在 127.0.0.1:8000 gunicorn -w 4 -b 127.0.0.1:8000 wsgi:app # 常用参数解释 # -w 4: 启动4个worker进程处理请求通常设为CPU核心数*21 # -b: 绑定地址和端口 # wsgi:app: wsgi是模块名即wsgi.pyapp是其中的Flask应用实例名 # --access-logfile -: 将访问日志打印到标准输出 # --error-logfile -: 将错误日志打印到标准错误输出7.2 使用Nginx作为反向代理Gunicorn擅长处理动态请求但不擅长处理静态文件如图片、CSS、JS。Nginx可以作为反向代理处理静态文件并将动态请求转发给Gunicorn同时还能提供负载均衡、SSL/TLS终止等功能。一个简单的Nginx配置示例/etc/nginx/sites-available/my_flask_blogserver { listen 80; server_name your_domain.com www.your_domain.com; # 你的域名 location / { # 将请求转发给运行在8000端口的Gunicorn 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; } # Nginx直接处理静态文件效率更高 location /static { alias /path/to/your/my_flask_blog/static; # 你的项目static目录绝对路径 expires 30d; # 设置客户端缓存30天 } }配置好后创建软链接到sites-enabled目录并测试、重载Nginx配置sudo ln -s /etc/nginx/sites-available/my_flask_blog /etc/nginx/sites-enabled/ sudo nginx -t # 测试配置语法 sudo systemctl reload nginx # 重载配置7.3 使用Supervisor管理进程你需要确保Gunicorn进程在服务器重启后能自动运行并且在崩溃时能自动重启。Supervisor是一个进程管理工具。安装Supervisor后创建一个配置文件/etc/supervisor/conf.d/my_flask_blog.conf[program:my_flask_blog] command/path/to/your/venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 wsgi:app ; 启动命令 directory/path/to/your/my_flask_blog ; 项目根目录 userwww-data ; 运行用户根据你的服务器用户设置 autostarttrue ; 随supervisor启动而启动 autorestarttrue ; 异常退出时自动重启 redirect_stderrtrue ; 重定向错误输出 stdout_logfile/var/log/my_flask_blog.log ; 日志文件路径 environmentPYTHONPATH/path/to/your/my_flask_blog ; 可选设置Python路径然后更新Supervisor并启动你的应用sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start my_flask_blog至此你的Flask应用就运行在一个相对稳定和安全的生产环境下了。当然真实的部署还涉及域名解析、HTTPS证书配置使用Let‘s Encrypt和Certbot、数据库备份、监控告警等更多步骤但以上是让一个Flask应用从本地走向公网最核心的几步。