Flask框架学习笔记
简介和安装
Flask是一个基于Python的轻量级Web应用框架,它简洁、易用,成为了许多开发人员的首选Python Web框架。
核心特点
- 轻量级: Flask是一个轻量级框架,核心功能相对较小,但通过扩展可以实现丰富的功能。
- 灵活: Flask提供了大量灵活性,开发人员可以选择适合其项目需求的工具和库。
- 易学易懂: 基于Python开发,使用了简洁的代码结构,使其容易学习和使用。
可以使用pip来安装Flask,运行以下命令:
pip install Flask
安装后,可以通过Pycharm创建一个Flask项目,项目结构如下
demo1/
static/
templates/
app.py
路由和视图函数
路由用于将URL映射到相应的视图函数,视图函数则负责处理请求并返回相应的内容。
请求
demo1/app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello 中国!'
@app.route("/profile")
def profile():
return "我是个人中心!"
@app.route("/blog/list")
def blog_list():
return "我是博客列表!"
# 传参方式一:将参数固定到了path中(GET)
@app.route("/blog/<int:blog_id>")
def blog_detail(blog_id):
return "您访问的博客是:%s" % blog_id
# 传参方式二:查询字符串的方式传参(GET)
# /book/list:会给我返回第一页的数据
# /book/list?page=2:获取第二页的数据
@app.route('/book/list')
def book_list():
# arguments:参数
# request.args:类字典类型
page = request.args.get("page", default=1, type=int)
return f"您获取的是第{page}的图书列表!"
# 传参方式三:表单传参(POST)
@bp.route("/qa/publish", methods=['POST'])
def publish_question():
form = QuestionForm(request.form)
title = form.title.data
content = form.content.data
print(title)
print(content)
# 1. debug模式:
# 1.1. 开启debug模式后,只要修改代码后保存,就会自动重新加载,不需要手动重启项目
# 1.2. 如果开发的时候,出现bug,如果开启了debug模式,在浏览器上就可以看到出错信息
# 2. 修改host:
# 主要的作用:就是让其他电脑能访问到我电脑上的flask项目
# 3. 修改port端口号:
# 主要的作用:如果5000端口被其他程序占用了,那么可以通过修改port来监听的端口号
if __name__ == '__main__':
app.run(debug=True)
响应
可以响应纯文本,HTML、JSON、文件,重定向
from flask import Flask,render_template,redirect,jsonify,send_file
@app.route('/')
def index():
return "hello world"
@app.route("/login")
def login():
return render_template('login.html')
@app.route('/hi')
def hi():
return redirect('/')
@app.route("/hello")
def hello():
return jsonify({"name":"xiaoming","age":16})
@app.route("/web")
def web():
return send_file("./small.png")
Jinja2模板系统
demo2/app.py
from flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)
def datetime_format(value, format="%Y年%m月%d日 %H:%M"):
return value.strftime(format)
app.add_template_filter(datetime_format, "dformat")
class User:
def __init__(self, username, email):
self.username = username
self.email = email
@app.route('/')
def hello_world():
user = User(username="张三", email="xx@qq.com")
person = {
"username": "李四",
"email": "lisi@qq.com"
}
return render_template("index.html", user=user, person=person)
@app.route("/blog/<blog_id>")
def blog_detail(blog_id):
return render_template("blog_detail.html", blog_id=blog_id, username="王五")
@app.route("/filter")
def filter_demo():
user = User(username="赵六xxxx", email="xx@qq.com")
mytime = datetime.now()
return render_template("filter.html", user=user, mytime=mytime)
@app.route("/control")
def control_statement():
age = 18
books = [{
"name": "三国演义",
"author": "罗贯中"
}, {
"name": "水浒传",
"author": "施耐庵"
}, ]
return render_template("control.html", age=age, books=books)
@app.route("/child1")
def child1():
return render_template("child1.html")
@app.route("/child2")
def child2():
return render_template("child2.html")
@app.route('/static')
def static_demo():
return render_template("static.html")
if __name__ == '__main__':
app.run()
给模板传入一般数据
demo2/templates/blog_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>博客详情</title>
</head>
<body>
<p>您的用户名是:{{ username }}</p>
<h1>您访问的博客详情是:{{ blog_id }}</h1>
</body>
</html>
给模板传入对象和字典
demo2/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
<div>{{ user.username }} / {{ user.email }}</div>
<div>{{ person['username'] }} / {{ person.username }}</div>
</body>
</html>
demo2/templates/filter.html: 自定义过滤器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤器使用demo</title>
</head>
<body>
<div>{{ user.username }}-{{ user.username|length }}</div>
<div>{{ mytime|dformat }}</div>
</body>
</html>
模板内的流程控制
demo2/templates/control.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>控制语句Demo</title>
</head>
<body>
{% if age>18 %}
<div>您已经满18岁,可以进入网吧!</div>
{% elif age==18 %}
<div>您刚满18岁,需要父母陪同才能进入!</div>
{% else %}
<div>您未满18岁,不能进入网吧!</div>
{% endif %}
{% for book in books %}
<div>图书名称:{{ book.name }},图书作者:{{ book.author }}</div>
{% endfor %}
</body>
</html>
模板的继承
demo2/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">新闻</a></li>
</ul>
{% block body %}
{% endblock %}
<footer>这是底部的标签</footer>
</body>
</html>
demo2/templates/child1.html
{% extends "base.html" %}
{% block title %}
我是子模板的标题
{% endblock %}
{% block body %}
我是子模板的body
{% endblock %}
demo2/templates/child2.html
{% extends "base.html" %}
{% block title %}
我是child2
{% endblock %}
{% block body %}
我是child2
{% endblock %}
模板中引用静态文件
demo2/templates/static.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/my.js') }}"></script>
</head>
<body>
<img src="{{ url_for('static', filename='images/ironman.jpg') }}" alt="">
</body>
</html>
SQLAlchemy ORM
ORM模型映射成表的三步
- flask db init:这步只需要执行一次
- flask db migrate:识别ORM模型的改变,生成迁移脚本
- flask db upgrade:运行迁移脚本,同步到数据库中
用MySQL数据库进行CURD
demo3/app.py
from flask import Flask, text
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
# 在app.config中设置好连接数据库的信息,然后使用SQLAlchemy(app)创建一个db对象
# SQLAlchemy会自动读取app.config中连接数据库的信息
HOSTNAME = "127.0.0.1"
PORT = 3306
USERNAME = "root"
PASSWORD = "123456"
DATABASE = "database_learn"
app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
db = SQLAlchemy(app)
migrate = Migrate(app, db)
# 直接执行SQL语句
# with app.app_context():
# with db.engine.connect() as conn:
# rs = conn.execute(text("select 1"))
# print(rs.fetchone()) # (1,)
class User(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
email = db.Column(db.String(100))
signature = db.Column(db.String(100))
# user = User(username="法外狂徒张三", password='111111')
# sql: insert user(username, password) values('法外狂徒张三', '111111');
class Article(db.Model):
__tablename__ = "article"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
content = db.Column(db.Text, nullable=False)
# 添加作者的外键
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
# backref:会自动的给User模型添加一个articles的属性,用来获取文章列表
author = db.relationship("User", backref="articles")
# 将模型同步为数据库中的表,但再修改模型后不能同步修改表
# with app.app_context():
# db.create_all()
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route("/user/add")
def add_user():
# 1. 创建ORM对象
user = User(username="法外狂徒张三", password='111111')
# 2. 将ORM对象添加到db.session中
db.session.add(user)
# 3. 将db.session中的改变同步到数据库中
db.session.commit()
return "用户创建成功!"
@app.route("/user/query")
def query_user():
# 1. get查找:根据主键查找
# user = User.query.get(1)
# print(f"{user.id}: {user.username}-{user.password}")
# 2. filter_by查找
# Query:类数组
users = User.query.filter_by(username="法外狂徒张三")
for user in users:
print(user.username)
return "数据查找成功!"
@app.route("/user/update")
def update_user():
user = User.query.filter_by(username="法外狂徒张三").first()
user.password = "222222"
db.session.commit()
return "数据修改成功!"
@app.route('/user/delete')
def delete_user():
# 1. 查找
user = User.query.get(1)
# 2. 从db.session中删除
db.session.delete(user)
# 3. 将db.session中的修改,同步到数据库中
db.session.commit()
return "数据删除成功!"
@app.route("/article/add")
def article_add():
article1 = Article(title="Flask学习大纲", content="Flaskxxxx")
article1.author = User.query.get(2)
article2 = Article(title="Django学习大纲", content="Django最全学习大纲")
article2.author = User.query.get(2)
# 添加到session中
db.session.add_all([article1, article2])
# 同步session中的数据到数据库中
db.session.commit()
return "文章添加成功!"
@app.route("/article/query")
def query_article():
user = User.query.get(2)
for article in user.articles:
print(article.title)
return "文章查找成功!"
if __name__ == '__main__':
app.run()
用sqlite做实验
demo3/test1.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
with app.app_context():
db.create_all()
RESTFul API
一个简单的基于RESTful风格的API示例,演示了如何使用HTTP动词对资源进行操作。
假设我们有一个用于管理书籍的API。我们可以有以下端点:
创建新书籍
- 请求方式: POST
- URL: /api/books
- 请求体:
{ "title": "The Catcher in the Rye", "author": "J.D. Salinger" }
- 示例响应:
{ "id": 3, "title": "The Catcher in the Rye", "author": "J.D. Salinger" }
更新特定书籍
- 请求方式: PUT/PATCH
- URL: /api/books/{id}
- 请求体:
{ "title": "New Title" }
- 示例响应:
{ "id": 3, "title": "New Title", "author": "J.D. Salinger" }
获取所有书籍
- 请求方式: GET
- URL: /api/books
- 示例响应:
[
{ "id": 1, "title": "1984", "author": "George Orwell" },
{ "id": 2, "title": "To Kill a Mockingbird", "author": "Harper Lee" }
]
获取特定书籍
- 请求方式: GET
- URL: /api/books/{id}
- 示例响应:
{ "id": 1, "title": "1984", "author": "George Orwell" }
删除特定书籍
- 请求方式: DELETE
- URL: /api/books/{id}
- 示例响应: 204 No Content
这些示例演示了如何使用RESTful风格设计简单的API。在实际开发中,需要考虑更多的安全性、身份验证、错误处理等方面。
问答平台项目
项目配置文件
demo4/config.py
SECRET_KEY = "asdfasdfjasdfjasd;lf" # 用于加密session
# 数据库配置
HOSTNAME = '127.0.0.1'
PORT = '3306'
DATABASE = 'database_learn'
USERNAME = 'root'
PASSWORD = '123456'
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
SQLALCHEMY_DATABASE_URI = DB_URI
# 邮箱配置
MAIL_SERVER = "smtp.qq.com"
MAIL_USE_SSL = True
MAIL_PORT = 465
MAIL_USERNAME = "yourqq@qq.com"
MAIL_PASSWORD = "zyvhrkyjcbzzbifg"
MAIL_DEFAULT_SENDER = "yourqq@qq.com"
解决循环引用问题
demo4/exts.py
from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail
db = SQLAlchemy()
mail = Mail()
项目入口
demo4/app.py
from flask import Flask, session, g
import config
from exts import db, mail
from models import UserModel
from blueprints.qa import bp as qa_bp
from blueprints.auth import bp as auth_bp
from flask_migrate import Migrate
app = Flask(__name__)
# 配置
app.config.from_object(config)
db.init_app(app)
mail.init_app(app)
# 迁移
migrate = Migrate(app, db)
# 注册蓝图 (blueprint:用来做块化模的)
app.register_blueprint(qa_bp)
app.register_blueprint(auth_bp)
# 钩子函数
# before_request/ before_first_request/ after_request
@app.before_request
def my_before_request():
user_id = session.get("user_id")
if user_id:
user = UserModel.query.get(user_id)
setattr(g, "user", user)
else:
setattr(g, "user", None)
@app.context_processor
def my_context_processor():
return {"user": g.user}
if __name__ == '__main__':
app.run(debug=True)
登录保护装饰器
demo4/decorators.py
from functools import wraps
from flask import g, redirect, url_for
def login_required(func):
# 保留func的信息
@wraps(func)
# func(a,b,c)
# func(1,2,c=3)
def inner(*args, **kwargs):
if g.user:
return func(*args, **kwargs)
else:
return redirect(url_for("auth.login"))
return inner
# @login_required
# def publish_question(quesiton_id):
# pass
#
# login_required(publish_question)(question_id)
ORM模型
demo4/model.py
from exts import db
from datetime import datetime
class UserModel(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(200), nullable=False)
email = db.Column(db.String(100), nullable=False, unique=True)
join_time = db.Column(db.DateTime, default=datetime.now)
class EmailCaptchaModel(db.Model):
__tablename__ = "email_captcha"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
email = db.Column(db.String(100), nullable=False)
captcha = db.Column(db.String(100), nullable=False)
class QuestionModel(db.Model):
__tablename__ = "question"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
create_time = db.Column(db.DateTime, default=datetime.now)
# 外键
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
author = db.relationship(UserModel, backref="questions")
class AnswerModel(db.Model):
__tablename__ = "answer"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
content = db.Column(db.Text, nullable=False)
create_time = db.Column(db.DateTime, default=datetime.now)
# 外键
question_id = db.Column(db.Integer, db.ForeignKey("question.id"))
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
# 关系
question = db.relationship(QuestionModel, backref=db.backref("answers", order_by=create_time.desc()))
author = db.relationship(UserModel, backref="answers")
注册、验证码、登录相关功能
demo4/blueprints/auth.py
from flask import Blueprint, render_template, jsonify, redirect, url_for, session
from exts import mail, db
from flask_mail import Message
from flask import request
import string
import random
from models import EmailCaptchaModel
from .forms import RegisterForm, LoginForm
from models import UserModel
from werkzeug.security import generate_password_hash, check_password_hash
# /auth
bp = Blueprint("auth", __name__, url_prefix="/auth")
# bp.route:如果没有指定methods参数,默认就是GET请求
@bp.route("/captcha/email")
def get_email_captcha():
# /captcha/email/<email>
# /captcha/email?email=xxx@qq.com
email = request.args.get("email")
# 4/6:随机数组、字母、数组和字母的组合
source = string.digits * 4
captcha = random.sample(source, 4)
captcha = "".join(captcha)
# I/O:Input/Output
# message = Message(subject="验证码", recipients=[email], body=f"您的验证码是:{captcha}")
# mail.send(message)
print(f"您的验证码是:{captcha}")
# memcached/redis
# 用数据库表的方式存储
email_captcha = EmailCaptchaModel(email=email, captcha=captcha)
db.session.add(email_captcha)
db.session.commit()
# RESTful API
# {code: 200/400/500, message: "", data: {}}
return jsonify({"code": 200, "message": "", "data": None})
@bp.route("/mail/test")
def mail_test():
message = Message(subject="邮箱测试", recipients=["kruskal666@163.com"], body="这是一条测试邮件")
mail.send(message)
return "邮件发送成功!"
# GET:从服务器上获取数据
# POST:将客户端的数据提交给服务器
@bp.route("/register", methods=['GET', 'POST'])
def register():
if request.method == 'GET':
return render_template("register.html")
else:
# 验证用户提交的邮箱和验证码是否对应且正确
# 表单验证:flask-wtf: wtforms
form = RegisterForm(request.form)
if not form.validate():
print(form.errors)
return redirect(url_for("auth.register"))
email = form.email.data
username = form.username.data
password = form.password.data
user = UserModel(email=email, username=username, password=generate_password_hash(password))
db.session.add(user)
db.session.commit()
return redirect(url_for("auth.login"))
@bp.route("/login", methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template("login.html")
else:
form = LoginForm(request.form)
if not form.validate():
print(form.errors)
return redirect(url_for("auth.login"))
email = form.email.data
password = form.password.data
user = UserModel.query.filter_by(email=email).first()
if not user:
print("邮箱在数据库中不存在!")
return redirect(url_for("auth.login"))
if not check_password_hash(user.password, password):
print("密码错误!")
return redirect(url_for("auth.login"))
# cookie:
# cookie中不适合存储太多的数据,只适合存储少量的数据
# cookie一般用来存放登录授权的东西
# flask中的session,是经过加密后存储在cookie中的
session['user_id'] = user.id
return redirect("/")
@bp.route("/logout")
def logout():
session.clear()
return redirect("/")
问答模块
demo4/blueprints/qa.py
from flask import Blueprint, request, render_template, g, redirect, url_for
from .forms import QuestionForm, AnswerForm
from models import QuestionModel, AnswerModel
from exts import db
from decorators import login_required
bp = Blueprint("qa", __name__, url_prefix="/")
# http://127.0.0.1:5000
@bp.route("/")
def index():
questions = QuestionModel.query.order_by(QuestionModel.create_time.desc()).all()
return render_template("index.html", questions=questions)
@bp.route("/qa/publish", methods=['GET', 'POST'])
@login_required
def publish_question():
if request.method == 'GET':
return render_template("publish_question.html")
else:
form = QuestionForm(request.form)
if not form.validate():
print(form.errors)
return redirect(url_for("qa.publish_question"))
title = form.title.data
content = form.content.data
question = QuestionModel(title=title, content=content, author=g.user)
db.session.add(question)
db.session.commit()
return render_template("detail.html", question=question)
@bp.route("/qa/detail/<qa_id>")
def qa_detail(qa_id):
question = QuestionModel.query.get(qa_id)
return render_template("detail.html", question=question)
# @bp.route("/answer/publish", methods=['POST'])
@bp.post("/answer/publish")
@login_required
def publish_answer():
form = AnswerForm(request.form)
if not form.validate():
print(form.errors)
return redirect(url_for("qa.qa_detail", qa_id=request.form.get("question_id")))
content = form.content.data
question_id = form.question_id.data
answer = AnswerModel(content=content, question_id=question_id, author_id=g.user.id)
db.session.add(answer)
db.session.commit()
return redirect(url_for("qa.qa_detail", qa_id=question_id))
@bp.route("/search")
def search():
# /search?q=flask
# /search/<q>
# post, request.form
q = request.args.get("q")
questions = QuestionModel.query.filter(QuestionModel.title.contains(q)).all()
return render_template("index.html", questions=questions)
表单数据验证模块
demo4/forms.py
import wtforms
from wtforms.validators import Email, Length, EqualTo, InputRequired
from models import UserModel, EmailCaptchaModel
from exts import db
# Form:主要就是用来验证前端提交的数据是否符合要求
class RegisterForm(wtforms.Form):
email = wtforms.StringField(validators=[Email(message="邮箱格式错误!")])
captcha = wtforms.StringField(validators=[Length(min=4, max=4, message="验证码格式错误!")])
username = wtforms.StringField(validators=[Length(min=3, max=20, message="用户名格式错误!")])
password = wtforms.StringField(validators=[Length(min=6, max=20, message="密码格式错误!")])
password_confirm = wtforms.StringField(validators=[EqualTo("password", message="两次密码不一致!")])
# 自定义验证:
# 1. 邮箱是否已经被注册
def validate_email(self, field):
email = field.data
user = UserModel.query.filter_by(email=email).first()
if user:
raise wtforms.ValidationError(message="该邮箱已经被注册!")
# 2. 验证码是否正确
def validate_captcha(self, field):
captcha = field.data
email = self.email.data
captcha_model = EmailCaptchaModel.query.filter_by(email=email, captcha=captcha).first()
if not captcha_model:
raise wtforms.ValidationError(message="邮箱或验证码错误!")
# else:
# # todo:可以删掉captcha_model
# db.session.delete(captcha_model)
# db.session.commit()
class LoginForm(wtforms.Form):
email = wtforms.StringField(validators=[Email(message="邮箱格式错误!")])
password = wtforms.StringField(validators=[Length(min=6, max=20, message="密码格式错误!")])
class QuestionForm(wtforms.Form):
title = wtforms.StringField(validators=[Length(min=3, max=100, message="标题格式错误!")])
content = wtforms.StringField(validators=[Length(min=3, message="内容格式错误!")])
class AnswerForm(wtforms.Form):
content = wtforms.StringField(validators=[Length(min=3, message="内容格式错误!")])
question_id = wtforms.IntegerField(validators=[InputRequired(message="必须要传入问题id!")])
模板及静态文件
略
概念
g和session
都是用于在请求处理过程中共享数据的机制,但它们有不同的作用和使用场景。
- g:适用于在同一个请求处理周期中需要共享数据的情况
- Session:适用于跨请求存储用户会话信息的情况
cookie和session
- cookie:在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
- session: session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器,不同的服务器,不同的框架,不同的语言有不同的实现。虽然实现不一样,但是他们的目的都是服务器为了方便存储数据的。session的出现,是为了解决cookie存储数据不安全的问题的。
cookie和session结合使用:web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式:
-
存储在服务端:通过cookie存储一个session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。
-
将session数据加密,然后存储在cookie中。这种专业术语叫做client side session。flask采用的就是这种方式,但是也可以替换成其他形式。