今天的操作流程
本节课所有代码都会在 本地编辑器 写好,然后用 FinalShell 拖到服务器 上运行。 保持"本地写、远程跑"的干净工作流。
Request 对象 —— 客户端送来的"快递包裹"
request 想象成一个快递包裹——用户从浏览器给后端发了个包裹,
里面可能装了输入框填的内容、上传的图片、URL 里的参数。用什么属性取什么东西:
| 属性 | 存什么 | 典型场景 |
|---|---|---|
request.args | URL 查询字符串参数 | 分页 ?page=2、搜索 ?q=flask |
request.form | POST 表单字段 | 登录、注册、发表留言 |
request.files | 上传的文件 | 头像、图片、附件 |
request.method | 请求方法 | 判断是 GET 还是 POST |
request.cookies | 客户端 Cookie | 读取登录凭证 |
用 request.args 接收 GET 参数
GET 参数就是 URL 里问号后面那一串:
http://192.168.1.100:5000/hello?name=鼎鼎&age=30
↑ ↑
路径 参数(key=value 用 & 连接)
📄 完整示例代码
# ========== 演示:接收 URL 上的 GET 参数 ==========
from flask import Flask, request
app = Flask(__name__)
# 路由:访问 /hello 时执行下面的函数
@app.route('/hello')
def hello():
# request.args 是一个字典,存放 URL 问号后面的所有参数
# .get('key', 默认值):参数没传时不会报错,会用默认值
name = request.args.get('name', '同学')
age = request.args.get('age', '未知')
# 直接返回 HTML 字符串(Flask 会帮我们变成网页)
return f'''
<h1>你好,{name}!</h1>
<p>你今年 {age} 岁了。</p>
'''
if __name__ == '__main__':
# host='0.0.0.0' 让外网能访问,必须这样写
# debug=True 代码改动后服务器会自动重启,调试时很方便
app.run(host='0.0.0.0', port=5000, debug=True)
▶️ 测试结果
http://IP:5000/hello?name=鼎鼎&age=30
→ 页面显示:"你好,鼎鼎!你今年 30 岁了。"
http://IP:5000/hello(什么都不传)
→ 页面显示:"你好,同学!你今年 未知 岁了。"(用了默认值)
request.args['name']——如果 URL 里没带 name 参数,程序会直接报错。
永远用 .get() 更安全。
用 request.form 接收表单提交
表单是用户在网页上填写的输入框。用户点"提交"后,数据通过 POST 请求发到服务器,
服务器用 request.form 读取。
显示空白表单
点"提交"按钮
浏览器发送数据
读 form,给响应
📄 完整示例代码(两个文件)
# ========== 演示:接收表单 POST 提交 ==========
from flask import Flask, request, render_template
app = Flask(__name__)
# 核心要点:methods=['GET','POST'] 让同一个路由同时接受两种请求
# GET → 显示表单页面;POST → 处理用户提交的数据
@app.route('/register', methods=['GET', 'POST'])
def register():
# 判断请求方法:是来填表(GET)还是来提交(POST)
if request.method == 'POST':
# request.form 是字典,读取 <input name="xxx"> 中 name 对应的值
username = request.form.get('username')
email = request.form.get('email')
hobby = request.form.get('hobby')
# 简单返回一个确认页面
return f'''
<h2>✅ 注册成功!</h2>
<p>用户名:{username}</p>
<p>邮 箱:{email}</p>
<p>爱 好:{hobby}</p>
<a href="/register">再填一次</a>
'''
# GET 请求:渲染 templates/form.html 给用户看
return render_template('form.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<h2>用户注册</h2>
<!-- 关键点:
method="POST" 表示用 POST 方式提交
action 不写表示提交到当前 URL
input 的 name 必须和 Python 里 request.form.get('xxx') 的 xxx 一致 -->
<form method="POST">
<p>用户名:<input type="text" name="username" required></p>
<p>邮 箱:<input type="email" name="email" required></p>
<p>爱 好:<input type="text" name="hobby"></p>
<button type="submit">注册</button>
</form>
</body>
</html>
▶️ 运行方式
# 进入项目目录,启动 Flask 应用
cd demo_form
python3 app.py
http://IP:5000/register → 看到注册表单2. 填入信息点"注册" → 页面跳到确认页,显示你刚才填的内容
3. 点"再填一次"回到表单页
<input name="username"> 的 name 属性,必须和 Python 里
request.form.get('username') 的字符串完全一致。
写错一个字母数据就取不到。
request.args.get() 取 URL 参数;POST 用 request.form.get() 取表单数据。
同一个路由要同时处理 GET 和 POST,记得加 methods=['GET', 'POST'] 和 if request.method == 'POST' 判断。
Cookie 和 Session —— 服务器怎么"记住"你
HTTP 协议是无状态的——每次请求之间是独立的,
服务器默认不记得你是谁。你在 /login 登录完,
下一秒访问 /home,服务器根本不知道是同一个人。
所以需要 Cookie 和 Session 这两个机制来"记住"用户。
Session 是景区后台的游客登记本——工作人员看到手环号,翻开登记本查到你是谁、买了什么票、哪天进的园。
Flask 的 session 对象把这两个机制都打包好了——我们只需要像操作字典一样操作它,细节 Flask 自动处理。
Session 登录的完整流程
账号密码
对就记录到 session
加密 Cookie
服务器认出你
Session 的三个核心操作
Flask 的 session 用起来就像一个字典:
# ① 登录时:把用户信息写入 session
session['user'] = 'admin'
# ② 任何时候:读取 session 判断是否登录
user = session.get('user') # 返回用户名 或 None
if user:
print('已登录:', user)
# ③ 退出时:从 session 中删除
session.pop('user', None) # 第二个参数 None:key 不存在也不报错
app.secret_key——它是用来加密 Session 数据的"钥匙"。没设这个会直接报错。app.secret_key = 'your-secret-key-xxx'
🎯 示例:完整的登录 / 退出系统
把前面学的全部串起来:一个最小的登录系统,有首页、登录页、退出三个路由。
# ========== 极简登录系统:Session 实战 ==========
from flask import Flask, request, session, redirect, url_for
app = Flask(__name__)
# 关键:必须设置 secret_key,Session 才能工作
# 实际项目要换成复杂的随机字符串,别直接照搬
app.secret_key = 'baoshan-university-flask-2026'
# ========== 路由 1:首页 ==========
@app.route('/')
def index():
# 从 session 取当前登录用户,没登录返回 None
user = session.get('user')
if user:
# 已登录:显示欢迎 + 退出按钮
return f'''
<h1>欢迎回来,{user}!👋</h1>
<p>这里是你的个人首页</p>
<a href="/logout">退出登录</a>
'''
# 未登录:提示去登录
return '''
<h1>你还没有登录</h1>
<a href="/login">点此登录</a>
'''
# ========== 路由 2:登录 ==========
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 从表单读取用户输入
username = request.form.get('username')
password = request.form.get('password')
# 简单硬编码验证:admin/123 才能登录
# 真实项目要查数据库 + 密码加密
if username == 'admin' and password == '123':
# ★ 核心一步:把用户信息写入 session
session['user'] = username
# redirect 跳转到首页,url_for 自动生成首页的 URL
return redirect(url_for('index'))
# 验证失败:提示错误
return '''
<h2>❌ 账号或密码错误</h2>
<a href="/login">重新登录</a>
'''
# GET 请求:返回登录表单
return '''
<h2>用户登录</h2>
<form method="POST">
<p>用户名:<input name="username" required></p>
<p>密 码:<input name="password" type="password" required></p>
<button>登录</button>
</form>
<p style="color:#888">提示:账号 admin,密码 123</p>
'''
# ========== 路由 3:退出 ==========
@app.route('/logout')
def logout():
# ★ 核心一步:从 session 中移除用户
session.pop('user', None)
# 跳回首页,此时首页会变回"未登录"状态
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
1. 访问 http://IP:5000/ → 显示"你还没有登录"
2. 点"点此登录" → 看到登录表单
3. 输入 admin / 123 → 点登录 → 自动跳回首页,变成"欢迎回来,admin!"
4. 点"退出登录" → 回到"你还没有登录"状态
5. 就算关掉浏览器再打开,只要 Cookie 没过期,首页还能认出你
session['user']=xxx、
读取 session.get('user')、删除 session.pop('user')。
配合 redirect(url_for(...)) 实现路由跳转,登录退出流程就完整了。
为什么要有模板继承?
一个网站往往有多个页面——首页、关于、联系我们……它们的导航栏和页脚都一样。 如果每个 HTML 都复制一遍,改导航就要改 N 次。
🎯 一个最小示例
两个文件演示模板继承:base.html 是父模板(骨架),
index.html 是子模板(填内容)。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>我的网站</title>
</head>
<body>
<!-- 所有页面共用的导航栏 -->
<nav><a href="/">首页</a> | <a href="/about">关于</a></nav>
<hr>
<!-- ★ 核心:挖一个"坑",名字叫 content,让子模板去填 -->
{% block content %}{% endblock %}
<hr>
<!-- 所有页面共用的页脚 -->
<footer>© 2026 保山学院</footer>
</body>
</html>
<!-- 第一行:声明继承哪个父模板 -->
{% extends 'base.html' %}
<!-- 填 content 这个"坑",里面写本页独有的内容即可 -->
{% block content %}
<h1>欢迎来到首页</h1>
<p>这里只需要写首页独有的内容,导航和页脚都从父模板继承。</p>
{% endblock %}
{% block 名字 %}{% endblock %} 挖坑;子模板用
{% extends '父模板' %} 继承;子模板用同名的
{% block %} 填坑。
💪 动手练习
做两个任务,把今天的知识点用起来。代码都已经写好并给出, 直接复制到本地保存成 .py 文件,用 FinalShell 拖到服务器运行。 重点是理解每一行代码在做什么,运行成功后记得截图保存。
任务 1:个人信息卡
基础 · 练习 7.1 GET 参数目标:写一个 Flask 程序,通过 URL 参数接收姓名、年龄、城市、专业, 在网页上显示成一张好看的个人信息卡。
访问示例:
http://IP:5000/card?name=鼎鼎&age=30&city=保山&major=人工智能
📄 完整代码
# ========== 任务 1:个人信息卡 ==========
# 知识点:用 request.args.get() 接收 URL 参数
from flask import Flask, request
app = Flask(__name__)
@app.route('/card')
def card():
# 从 URL 中读取 4 个参数,每个都有默认值
# 语法:request.args.get('参数名', '默认值')
name = request.args.get('name', '匿名')
age = request.args.get('age', '保密')
city = request.args.get('city', '未知')
major = request.args.get('major', '未填')
# 返回带简单样式的 HTML(f-string 可以在字符串里嵌入变量)
# 注意:f-string 中的 CSS 花括号要写成 {{ }} 来转义
return f'''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>个人信息卡</title>
<style>
body {{
font-family: sans-serif;
background: #F4F7FB;
display: flex;
justify-content: center;
padding-top: 50px;
}}
.card {{
background: white;
padding: 30px 40px;
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0,0,0,0.08);
width: 340px;
border-top: 4px solid #3B6B9A;
}}
h1 {{ color: #1E3A5C; margin: 0 0 20px; }}
p {{ color: #334155; line-height: 1.8; margin: 6px 0; }}
.label {{ color: #64748B; display: inline-block; width: 60px; }}
</style>
</head>
<body>
<div class="card">
<h1>👤 {name}</h1>
<p><span class="label">年龄</span>{age}</p>
<p><span class="label">城市</span>{city}</p>
<p><span class="label">专业</span>{major}</p>
</div>
</body>
</html>
'''
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
▶️ 运行步骤
# 1. 本地创建 task1_card 文件夹,把上面的 app.py 放进去
# 2. 用 FinalShell 拖到服务器
# 3. 在服务器终端运行:
cd task1_card
python3 app.py
浏览器访问:
http://服务器IP:5000/card?name=鼎鼎&age=30&city=保山&major=人工智能
自己尝试:改 URL 里的参数值,看页面怎么变;
再尝试:不传任何参数直接访问 /card,看默认值效果。
任务 2:带登录保护的个人主页
综合 · 练习 7.1 + 7.2目标:实现一个需要登录才能访问的个人主页。未登录用户访问 /profile
会被自动踢回登录页;登录成功后才能看到主页内容。
提供两个账号:admin / 123 和 user / 456
涉及的路由:
/—— 首页,显示登录状态/login—— 登录页(GET 显示表单,POST 处理提交)/profile—— 个人主页(必须登录才能访问)/logout—— 退出登录
📄 完整代码
# ========== 任务 2:带登录保护的个人主页 ==========
# 知识点:request.form(表单)+ session(登录状态)+ redirect(跳转)
from flask import Flask, request, session, redirect, url_for
app = Flask(__name__)
# Session 必须配置 secret_key
app.secret_key = 'task2-secret-key-change-me'
# 允许的用户字典:key 是用户名,value 是密码
# 用字典比写好几个 if-else 优雅得多
USERS = {
'admin': '123',
'user': '456',
}
# ========== 路由 1:首页 ==========
@app.route('/')
def index():
user = session.get('user')
if user:
return f'''
<h1>👋 欢迎 {user}</h1>
<p><a href="/profile">进入个人主页</a></p>
<p><a href="/logout">退出登录</a></p>
'''
return '''
<h1>欢迎来到本站</h1>
<p>你还没登录,<a href="/login">点此登录</a></p>
'''
# ========== 路由 2:登录 ==========
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# 用字典校验:如果用户名存在 且 密码匹配
if USERS.get(username) == password:
session['user'] = username
# 登录成功:跳到个人主页
return redirect(url_for('profile'))
# 验证失败
return '''
<h2>❌ 账号或密码错误</h2>
<a href="/login">重新登录</a>
'''
# GET:显示登录表单
return '''
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>登录</title></head>
<body style="font-family:sans-serif; max-width:360px; margin:60px auto;">
<h2>🔐 用户登录</h2>
<form method="POST">
<p>用户名:<input name="username" required></p>
<p>密 码:<input name="password" type="password" required></p>
<button>登录</button>
</form>
<p style="color:#888; font-size:13px;">
测试账号:admin/123 或 user/456
</p>
</body>
</html>
'''
# ========== 路由 3:个人主页(需要登录才能看)==========
@app.route('/profile')
def profile():
# ★ 这里是重点:先检查有没有登录
user = session.get('user')
if not user:
# 没登录:踢回登录页
return redirect(url_for('login'))
# 已登录:展示个人主页
return f'''
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>个人主页</title></head>
<body style="font-family:sans-serif; max-width:500px; margin:40px auto;">
<h1>🏠 这是 {user} 的个人主页</h1>
<p>只有登录用户才能看到这个页面。</p>
<p>当前登录账号:<strong>{user}</strong></p>
<hr>
<p>
<a href="/">返回首页</a> |
<a href="/logout">退出登录</a>
</p>
</body>
</html>
'''
# ========== 路由 4:退出登录 ==========
@app.route('/logout')
def logout():
# 从 session 中删除用户信息
session.pop('user', None)
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
▶️ 运行步骤
cd task2_login
python3 app.py
① 没登录直接闯关:访问 /profile → 应该被自动踢到 /login
② 错误密码:输入 admin/999 → 显示"账号或密码错误"
③ 正确登录:输入 admin/123 → 跳到个人主页显示"这是 admin 的个人主页"
④ 换账号:退出后用 user/456 登录 → 主页显示"这是 user 的个人主页"
⑤ 退出:点"退出登录" → 回到首页,再访问 /profile 又被踢走
/profile 里第一件事就是检查 session.get('user')?因为任何人都能在地址栏输入 URL——只检查"来的路径"靠不住,必须检查"这个用户是不是登录了"。 这就是后端安全的第一课:永远不要相信前端传来的任何东西。
📤 练习交付要求
- 两个任务独立目录:
task1_card/和task2_login/ - 本地保存代码 → FinalShell 拖到服务器 →
python3 app.py→ 浏览器测试 → 截图运行效果 - 截图要包含:URL 地址栏 + 页面显示效果
Ctrl+C 停掉上一个程序,
不然会报错"Address already in use"。也可以把第二个任务的 port=5000 改成 port=5001。