跳至主要內容

上下文

Mr.Liu大约 5 分钟

上下文

上下文:即语境,语意,在程序中可以理解为在代码执行到某个时刻,根据之前代码锁做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以做的事情。

上下文对象

Flask中有两种上下文:请求上下文(request context)应用上下文(application context)

Flask中上下文对象:相当于一个容器,保存了Flask程序运行过程中的一些信息。

RequestContext

Flask中,可以直接在视图函数中使用request这个独享进行获取相关数据,而request就是请求上下文对象,保存了本次请求的相关数据。请求上下文对象有:requestsession

Request

Request 请求的对象。封装了HTTP请求的内容,针对的是http请求。

flask在每个请求产生后自动激活当前请求的上下文,激活请求上下文后,request被临时设为全局可访问。当每个请求结束后,flask就销毁对应的请求上下文。

在前面说request是全局对象,但这里的全局并不是实际意义上的全局。我们把这些变量理解为动态的全局变量。

在多线程服务中,在同一时间可能会有多个请求在处理。假设有三个客户端同时向服务器发送请求,这时每个请求都有各自不同的请求报文,所以请求对象必然是不同的。

因此,请求对象只在各自的线程内是全局的。flask通过本地线程(thread local)技术将请求对象在特定的线程和请求中全局可访问。

例如:

  • user = request.args.get('user'),获取的是get请求的参数。

Session

Session 根据请求中的cookie,重新载入该访问者相关的会话信息,针对的是用户信息。例如:

  • session['name'] = user.id 可以记录用户信息。
  • session.get('name')可以获取用户信息。

ApplicationContext

它不是一直存在的,它只是request context中的一个对app的代理,所谓的local proxy。它的作用主要是帮助request获取当前的应用,它是伴request而生,随request而灭的。应用上下文对象有:current_app,g

current_app

current_app 当前激活程序的程序实例。程序会有多个程序实例的情况,为了能获取对应的程序实例,而不是固定的某一个程序实例,我们就需要使用current_app变量。

用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:

  • 应用的启动脚本是哪个文件,启动时指定了哪些参数
  • 加载了哪些配置文件,导入了哪些配置
  • 连接了哪个数据库
  • 有哪些可以调用的工具类、常量
  • 当前flask应用在哪个机器上,哪个IP上运行,内存多大

g

g g存储在程序上下文中,而程序上下文会随着每一个请求的进入而激活,随着每一个请求的处理完毕而销毁,所以每次请求都会重设这个g值。

我们通常会使用它结合钩子来保存每个请求处理前所需要的全局变量。

g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别。

from flask import Flask, g

app = Flask(__name__)

def db_query():
    user_id = g.user_id
    user_name = g.user_name
    print('user_id={} user_name={}'.format(user_id, user_name))

@app.route('/')
def get_user_profile():
    g.user_id = 131
    g.user_name = 'Jeremy'
    db_query()
    return 'hello world'

生命周期

  • current_app的生命周期最长,只要当前程序实例还在运行,都不会失效。
  • Requestg的生命周期为一次请求期间,当请求处理完成后,生命周期也就完结了
  • Session就是传统意义上的session了。只要它还未失效(用户未关闭浏览器、没有超过设定的失效时间),那么不同的请求会共用同样的session

手动开启上下文

from flask import Flask, current_app
 
app = Flask(__name__)
print(app)    #输出结果:<Flask 'app'>
app2 = current_app
print(app2)    #输出结果:竟然报了一大堆的错误

错误信息是这样子的:RuntimeError: Working outside of application context。意思是说我们在应用上下文之外运行的。

同样的问题还有类似的情况:

from flask import Flask, request

app = Flask(__name__)
print(request.args)  # 同样报错

错误信息是这样子的:RuntimeError: Working outside of request context。意思是说我们在请求上下文之外运行的。

这究竟是咋回事?

在flask程序未运行的情况下, 调试代码或进行测试, 同样需要使用current_app, g, request这些对象, 但程序未运行, 所以无法使用, 此时需要手动开启上下文。

app_context

app_context为我们提供了应用上下文环境, 允许我们在外部使用应用上下文current_app, g,可以通过with语句进行使用:

from flask import Flask, current_app

app = Flask(__name__)
with app.app_context():  # 借助with语句使用app_context创建应用上下文
    print(current_app)  # <Flask 'app'>

request_context

request_context为我们提供了请求上下文环境,允许我们在外部使用请求上下文requestsession,可以通过with语句进行使用:

from flask import Flask, request

app = Flask(__name__)

environ = {
    'wsgi.version': (1, 0),
    'wsgi.input': '',
    'REQUEST_METHOD': 'GET',
    'PATH_INFO': '/',
    'SERVER_NAME': 'bookandmusic server',
    'wsgi.url_scheme': 'http',
    'SERVER_PORT': '80'
}  # 模拟解析客户端请求之后的wsgi字典数据
with app.request_context(environ):  # 借助with语句使用request_context创建请求上下文
    print(request.method)