看了加薪, Flask里需要了解的5个全局对象用法

在一个python flask的应用开发中,  经常会遇到需要跨函数, 路由或者请求来共用数据或参数的情况,  笔者先提2个问题: 如果要在多个请求中共用一个信息,比如同一个用户多次post中的用户信息,应该怎么处理?  大型分布式网站如何确保用户取到一致的信息? 

这和变量的作用域有关. 一般跨函数,路由或请求的信息共用考虑使用全局对象,在具体的flask业务中, 有g, session, request, current_app, 和 缓存如redis可以考虑.  他们的区别和使用分别是怎么样的呢? 一起来看下: 

1. g

  • 原理g 是 Flask 提供的一个全局对象,用于在处理单个请求的过程中存储和共享数据。它是临时的,数据只在当前请求的生命周期内存在,处理完请求后会被清除。

  • 作用范围:只在当前请求中有效,不同的请求不会共享 g 中的数据。

  • 典型用途:在请求过程中传递数据库连接、用户信息等。

  • 示例

from flask import Flask, g

app = Flask(__name__)

@app.before_request
def before_request():
    # 设置临时数据,比如当前用户
    g.user = "Alice"

@app.route('/')
def index():
    # 访问 `g` 中的临时数据
    return f"Hello, {g.user}!"

2. session

  • 原理session 是一个字典,用于在客户端和服务器之间持久化存储用户的会话数据,比如登录状态、用户偏好等。它的数据存储在客户端的 Cookie 中,并由服务器进行签名和加密以防篡改。

  • 作用范围session 在客户端和服务器之间共享,可以跨请求使用,直到会话结束或手动清除。

  • 典型用途:管理用户登录状态、存储用户数据。

  • 示例

from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = 'supersecretkey'

@app.route('/login', methods=['POST'])
def login():
    # 登录成功后将用户信息存储到 session
    session['user'] = request.form['username']
    return redirect(url_for('index'))

@app.route('/')
def index():
    if 'user' in session:
        return f"欢迎回来, {session['user']}!"
    return "您还未登录。"

@app.route('/logout')
def logout():
    session.pop('user', None)
    return redirect(url_for('index'))

3. request

  • 原理request 对象表示客户端发来的 HTTP 请求,包含所有请求相关的数据,如请求方法、表单数据、查询参数、请求头等。

  • 作用范围request 对象只在当前请求中有效,不同请求间的数据相互独立。

  • 典型用途:获取和处理客户端发来的数据。

  • 示例

from flask import Flask, request

app = Flask(__name__)

@app.route('/submit', methods=['POST'])
def submit():
    username = request.form.get('username')
    return f"提交的用户名是: {username}"

4. current_app

  • 原理current_app 是一个指向当前 Flask 应用实例的代理对象,用于在请求上下文中访问应用实例。它可以用来获取应用的配置、日志记录器等。

  • 作用范围:只能在应用上下文中使用(例如请求处理过程中)。

  • 典型用途:访问应用配置、记录日志。

  • 示例

from flask import Flask, current_app

app = Flask(__name__)
app.config['MY_SETTING'] = '设置值'

@app.route('/')
def index():
    setting_value = current_app.config['MY_SETTING']
    return f"应用配置值: {setting_value}"

5. _request_ctx_stack

  • 原理_request_ctx_stack 是 Flask 内部使用的一个栈结构,用于管理请求上下文。每当一个请求到达时,Flask 会创建一个新的请求上下文,并将其推入 _request_ctx_stack,处理完请求后再将其弹出。这确保了请求相关的数据(如 grequest)在不同的请求中是独立的。

  • 作用范围:主要用于内部处理,不直接用于业务逻辑中。

  • 典型用途:确保在多线程或异步环境中,不同的请求可以独立管理自己的上下文数据。

  • 示例:这个对象通常不直接使用,主要是 Flask 用来处理上下文的管理机制。

总结

g:用于当前请求的临时存储,生命周期仅限于单个请求。

session:用于跨请求的用户数据存储,数据持久化在客户端 Cookie 中。

request:表示当前的 HTTP 请求,包含所有请求相关的信息。

current_app:指向当前 Flask 应用实例的代理,用于访问应用级别的信息。

_request_ctx_stack:内部机制,用于管理请求上下文,确保每个请求都有独立的上下文环境。由于_request_ctx_stack 是flask内部使用, 我们转向讨论缓存/redis来作为第五种用法:

缓存

还有web应用中常用的cache机制如Redis, Memcached, 数据库等别忘了, 以使用较普遍的redis为例, 大型分布式网站常用的一个做法就是将session信息缓存与统一的redis集群,方便在负载均衡的情况下, 用户访问时能够取到一致的缓存信息避免分裂问题. 

以Redis为例, Redis 是一个高性能的键值存储数据库,常用于缓存、会话管理、消息队列等场景。使用 Redis 可以帮助提升 Flask 应用的性能和响应速度,特别是当某些数据需要频繁访问,但更新较少的情况下。

在 Flask 中使用 Redis 的场景

  1. 跨请求共享数据:Flask 的 session 数据存储在客户端 Cookie 中,而如果你有需要跨请求共享但不适合放在客户端的数据(如临时统计数据、用户状态等),Redis 可以作为后端缓存存储。

  2. 函数级缓存:对于一些计算复杂、结果不经常变化的函数,可以将计算结果缓存到 Redis 中,避免重复计算。这种场景在 Flask 中特别常见,比如:数据库查询、API 调用结果缓存。

  3. 全局状态管理:如果应用中有一些全局状态需要在多个请求中保持一致,如访问统计、在线用户数等,Redis 可以作为一个高效的状态管理工具。

  4. 分布式会话管理:在多台服务器上运行 Flask 应用时,使用 Redis 可以实现会话共享。用户的会话数据存储在 Redis 中,所有的服务器实例都可以访问这些会话数据,从而实现分布式会话管理。

  5. 任务队列和消息队列:Flask 中配合 Celery 使用 Redis,可以实现异步任务队列,提升应用的响应速度。

如何在 Flask 中集成 Redis

以下是一个使用 Redis 缓存数据的示例:

示例:使用 Redis 缓存数据
from flask import Flask, request, jsonify
import redis
import time

app = Flask(__name__)

# 连接 Redis
cache = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)

def cache_data(key, value, timeout=60):
    """
    将数据缓存到 Redis 中
    :param key: 缓存的键
    :param value: 缓存的值
    :param timeout: 缓存的过期时间(秒)
    """
    cache.setex(key, timeout, value)

def get_cached_data(key):
    """
    从 Redis 中获取缓存数据
    :param key: 缓存的键
    :return: 缓存的值,如果不存在则返回 None
    """
    return cache.get(key)

@app.route('/data')
def get_data():
    key = 'expensive_data'
    # 先检查缓存
    data = get_cached_data(key)
    if data:
        return jsonify({"source": "cache", "data": data})

    # 模拟数据获取过程,例如复杂计算或数据库查询
    data = f"Computed data at {time.time()}"
    # 缓存结果
    cache_data(key, data, timeout=30)  # 缓存 30 秒
    return jsonify({"source": "computed", "data": data})

if __name__ == '__main__':
    app.run()

示例代码解释

  1. 连接 Redis:使用 redis.StrictRedis 连接到 Redis 服务器。

  2. 缓存数据cache_data 函数将数据存入 Redis,设置一个超时时间来自动清理过期数据。

  3. 获取缓存数据get_cached_data 函数尝试从 Redis 获取缓存数据,如果存在就直接返回。

  4. 数据获取逻辑:在 Flask 路由中,首先检查缓存是否命中,如果命中直接返回缓存数据,否则进行计算并将结果缓存。

回到开头提出的问题: 如果要在多个请求中共用一个信息,比如同一个用户多次post中的用户信息,应该怎么处理?  大型分布式网站如何确保用户取到一致的信息? 

1. 同一个用户多次post中的用户信息,可以用session来处理

2. 大型分布式网站可以用redis来存储用户session信息确保分布式应用取到一致信息

关注生产力联盟, 为组织和个人提高生产力。欢迎关注留言交流.

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值