Flask的request是从哪里来的

2024-02-05 13:32
文章标签 flask request 是从

本文主要是介绍Flask的request是从哪里来的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

从一个简单的 Flask 示例开始。

from flask import Flask, requestapp = Flask(__name__)@app.route('/')
def index():print(request.headers)return 'Hello World!'if __name__ == '__main__':app.run()

调试程序,在客户端输入 http://localhost:5000,浏览器显示 Hello World,在 IDE 中显示了请求头的信息。看起来,request 对象像一个全局变量,导入后就可以直接使用。那么,我们将 print 语句变一个位置:

if __name__ == '__main__':print(request.headers)app.run()

这个时候,程序出错了,抛出如下面所示的异常:

RuntimeError: Working outside of request context.

意思是 request 不在 context 之中。为什么在视图函数中可以直接使用 request,而在 app.run() 代码之前就不行呢?这就引出了一个请求上下文 (request context) 的概念。我们知道,web 程序启动后,在同一时间,可能来自多个客户端的请求,这些请求是不同的,有着各自不同的请求报文。服务器对来自不同客户端的请求,必须能够单独进行处理,互不干扰。Flask 用请求上下文 (request context) 来实现对来自不同客户端的请求能独立处理,又让开发人员在编写代码的时候,request 像一个全局变量

那么,这个 request 是怎么来的呢?为什么在导入后就可以直接使用?本文将从代码的角度,对 Flask 背后的机制进行剖析。结合在 PyCharm 中对代码的调试和 Flask 源代码功能进行讲解。在 app.run() 语句打一个断点:

调试到该语句,变量区域显示 request 是一个 LocalProxy 对象,此时 request 的状态为 unbound,并没有跟实际来自客户端的请求绑定。

接着按 F8,我们看到,Flask 已经启动,等待客户端请求。先来看看截止这个阶段与 request 相关的代码。从 from flask import request 语句跳转到源代码。代码位于 globals.py 文件中,主要的代码如下:

# context locals
_request_ctx_stack = LocalStack()
_app_ctx_stack = LocalStack()
current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_req_object, "request"))
session = LocalProxy(partial(_lookup_req_object, "session"))
g = LocalProxy(partial(_lookup_app_object, "g"))

因为有 import 语句,所以 globals.py 的代码被加载,request 被实例化。

接下来我们看看 app.run() 做了什么。如果调试该代码,就进入 Flask 类的 run() 方法。去掉 run() 方法无关的代码,该方法可以简化为:

def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):# 去掉无关代码# ...run_simple(host, port, self, **options)

这个 run_simple 方法是 werkzeug.serving 模块提供的方法,作用是启动一个服务器。我们可以自己写一段简单代码来体验一下 werkzeug 实现的这个简单服务器:

from werkzeug.wrappers import Response, Request
from werkzeug.serving import run_simple@Request.application
def simple_app(req):return Response("Hello from werkzeug!")run_simple(hostname="127.0.0.1", port=9000, application=simple_app)

Flask 的代码复杂得多,但机制相同。

接下来,看看 Flask 如何处理来自客户端的请求。当客户端发起请求后,web server 将请求转交给后端 Flask application,此时就调用 Flask 的 __call__() 方法。Flask __call__() 方法的代码如下:

def __call__(self, environ, start_response):return self.wsgi_app(environ, start_response)

所以,对来自客户端的请求,会自动调用 __call__() 方法,启动 wsgi_app。下面的代码是 request 机制的核心:

def wsgi_app(self, environ, start_response):ctx = self.request_context(environ)  error = Nonetry:try:ctx.push()response = self.full_dispatch_request()except Exception as e:error = eresponse = self.handle_exception(e)except:  # noqa: B001error = sys.exc_info()[1]raisereturn response(environ, start_response)finally:if self.should_ignore_error(error):error = Nonectx.auto_pop(error)

与 request 相关的有两句代码:

ctx = self.request_context(environ) # 创建RequestContext实例,其中包含request
ctx.push()                          # RequestContext对象入栈

通过查看代码调试的方式,运行机制不难理解。首先,request_context是一个函数,返回 RequestContext:

def request_context(self, environ):return RequestContext(self, environ)

RequestContext类的 __init__() 方法根据 environ (环境变量) 构建请求。__enter____exit__ 方法实现了上下文管理。如果不关注更细节东西,至此基本基本可以理解请求的机制。

class RequestContext(object):def __init__(self, app, environ, request=None, session=None):self.app = appif request is None:request = app.request_class(environ)self.request = request# 其他代码略

request_class 声明在 Flask app.py 代码中,其实就是 werkzeug.wrappers.Request

总结:Flask 通过请求上下文,自动管理每个 HTTP 请求的生命周期。当接收到客户端的请求,创建一个新的 request 对象,包含请求报文信息。当请求结束时,自动销毁请求

这篇关于Flask的request是从哪里来的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/681070

相关文章

Vue3上传图片报错:Current request is not a multipart request

当你看到错误 "Current request is not a multipart request" 时,这通常意味着你的服务器或后端代码期望接收一个 multipart/form-data 类型的请求,但实际上并没有收到这样的请求。在使用 <el-upload> 组件时,如果你已经设置了 http-request 属性来自定义上传行为,并且遇到了这个错误,可能是因为你在发送请求时没有正确地设置

使用http-request 属性替代action绑定上传URL

在 Element UI 的 <el-upload> 组件中,如果你需要为上传的 HTTP 请求添加自定义的请求头(例如,为了通过身份验证或满足服务器端的特定要求),你不能直接在 <el-upload> 组件的属性中设置这些请求头。但是,你可以通过 http-request 属性来自定义上传的行为,包括设置请求头。 http-request 属性允许你完全控制上传的行为,包括如何构建请求、发送请

code: 400, msg: Required request body is missing 错误解决

引起这个错误的原因是,请求参数按照get方式给。 应该给json字符串才对 补充: 1. @RequestBody String resource 加@RequestBody必须给json字符串,否则会报错400,记如标题错误。 不加这个的进行请求的话,其实post和get就没有什么区别了。 2. List<String> indexCodes=(List<String>)json.

flask-login 生成 cookie,session

flask-login 生成 cookie,session Flask-Login login_user() 显示来自 Set-Cookie 标头的加密 cookie # 模拟一个用户类class User(UserMixin):def __init__(self, id):self.id = id@app.route('/login')def login():# 模拟用户登录过程user

FORM的ENCTYPE=multipart/form-data 时request.getParameter()值为null问题的解决

此情况发生于前台表单传送至后台java servlet处理: 问题:当Form需要FileUpload上传文件同时上传表单其他控件数据时,由于设置了ENCTYPE=”multipart/form-data” 属性,后台request.getParameter()获取的值为null 上传文件的参考代码:http://www.runoob.com/jsp/jsp-file-uploading.ht

Flask 创建app 时候传入的 static_folder 和 static_url_path参数理解

Flask 在创建app的时候 是用 app = Flask(__name__) 来创建的,不传入 static_folder参数的话 ,默认的静态文件的位置是在 static目录下 我们可以进入 Flask的源码里面查看 ctrl+鼠标左键进入 这是Flask的 __init__源码(后面还有一些,我就选了需要的代码)     def __init__(self,import_

兔子-(PHP 5.3 and above) Please set 'request_order' ini value to include C,G and P (recommended: 'CGP'

由于在PHP最新的版本中增加了一个配置项目“request_order”,默认值为“GP”,这个存在一定的安全风险。这里我们建议用户将配置更改为“CGP” 可以在php的安装目录下找到php.ini配置目录,找到下面选项: request_order = "GP"  更改为 request_order = "CGP"   重启服务器后即可。 此

【python 爬虫】python如何以request payload形式发送post请求

普通的http的post请求的请求content-type类型是:Content-Type:application/x-www-form-urlencoded, 而另外一种形式request payload,其Content-Type为application/json import jsonurl = 'https://api.github.com/some/endpoint'payload

【python web】Flask+Echarts 实现动图图表

flask 是python web开发的微框架,Echarts酷炫的功能主要是javascript起作用,将两者结合起来,发挥的作用更大。下面将Echarts嵌套进Flask的html模板中。 项目结构: 打开demo.py运行,点击console中的链接http://127.0.0.1:5000/ 就可以看到我们想要的动态图表。 demo.py #coding:utf-8fro

【python requests警告】python3.x requests库取消ssl验证,InsecureRequestWarning: Unverified HTTPS request is be

警告信息: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warni