42Team-Flask框架-请求与响应
请求-响应循环
上一个章节写了一个简单的Flask程序,那么Flask的工作方式你是否好奇?下面会简单介绍一些Flask框架的设计理念。
应用和请求上下文
Flask收到来自浏览器客户端的请求后,需要让视图函数获取到一些对象,这样才能更好地处理请求。所以Flask用请求对象来封装浏览器发送的HTTP请求,Flask使用请求上下文来临时的把某些对象变为全局可访问的对象。有了请求上下文,就可以获取得到浏览器客户端发给服务器端的HTTP请求了,其中抱恨用户提交的表单、请求头等。
1 |
|
request.headers.get('User-Agent')
可以获得客户端使用的浏览器的一些基本信息。
如果你想用request,需要从flask中导入request。你需要注意的是在这个视图函数中,我们把request当作一个全局变量来使用了。事实上,request不可能是全局变量,假设这时候有很多用户同时访问我们的服务。如果request是全局变量的话就会导致数据混乱,所以在多线程服务器中,每个线程同时处理着不同用户客户端发过来的数据,那么必然每个线程所使用的request也是不同的。Flask使用上下文让特定变量在一个线程在他的生面周期内可以访问,并且不会干扰其他线程。
线程是可单独管理的最小指令集,进程通常使用多个活动线程,有时候还会共享内存和文件句柄等其他资源。通常多线程Web服务器例如Flask会创建一个线程池,如果有客户访问服务器,那么会从线程池中抽出一个线程处理客户端发出的请求。
在Flask中有两种上下文:
- 应用上下文
- 请求上下文
变量名 | 类型 | 说明 |
---|---|---|
request | 请求上下文 | 请求对象。它封装了客户端发出的HTTP请求中的内容 |
session | 请求上下文 | 用户会话,它的值是字典,解决HTTP协议无法维持回话的情况。 |
g | 应用上下文 | 处理请求时用作临时存储的对象,每次请求都会重设这个变量 |
current_app | 应用上下文 | 当前应用的应用实例 |
Flask在分派请求之前激活应用和请求上下文,该请求处理完成后会将其删除,也就是说在该用户线程运行结束后,会将一些上下文删除。当应用上下文被推送后,就可以在当前线程内使用current_app和g变量。同理当激活请求上下文后当前线程也可以使用request、session请求上下文。
如果不太理解这些概念也没有关系,后续我们会经常使用到。
请求分派
服务端接收到客户端发送的请求时,要找到处理该请求的对应的视图函数,Flask会在URL映射中查找请求的URL。URL映射是URL和视图函数之间的对应关系。Flask使用@app.route()
装饰器来构建。
1 |
|
将/hello
URL映射到index()
视图函数中。如果你有点忘记了视图函数和路由这些概念你可以回去看看《路由和视图》。完整的路由和视图操作叫做请求分派。
request请求对象
Flask通过请求上下文request
来对外开放请求对象。请求对象很有用,它包含了客户端浏览器发送的HTTP全部请求信息。下表中列出所有请求对象常用属性和方法。
属性或方法 | 返回类型 | 说明 |
---|---|---|
form | 字典 | 存储请求提交的所有表单字段 |
args | 字典 | 存储通过URL查询字符串传递的所有参数 |
values | 字典 | form 和args 的合集 |
cookies | 字典 | 存储请求的所有cookie |
headers | 字典 | 存储请求的所有HTTP请求头 |
files | 字典 | 存储请求上传的所有文件 |
method | 字符串 | 返回当前HTTP请求方法 |
is_secure | 布尔 | 是否使用可靠的HTTPS加密连接 |
endpoint | 字符串 | 返回处理当前请求的视图函数的函数名 |
scheme | 字符串 | URL 方案(http 或 https) |
host | 字符串 | 请求定义的主机名,如果客户端其定义了端口号,还包括端口号 |
remote_addr | 字符串 | 客户端的发送HTTP请求的IP地址 |
path | 字符串 | URL的路径部分 |
url | 字符串 | 客户端请求的完成URL |
get_data() | 返回请求主体缓冲的数据 |
请求钩子
使用请求钩子可以在处理视图函数前进行额外的操作,可以用于建立数据库连接或者验证用户身份。当然也可以请求结束后执行的额外的操作,比如关闭数据库连接等。
请求钩子 | 说明 |
---|---|
before_request | 在每次请求前执行 |
before_first_request | 仅第一次请求时执行 |
after_request | 如果没有未处理的异常,会在请求结束后执行 |
teardown_request | 即使有未处理的异常,也会在请求结束后执行 |
在钩子函数和视图函数之间共享数据一般使用上下文全局变量g。例如before_request 处理程序可以从数据库中加载已登录用户,并将其保存到 g.user 中。随后调用视图函数时,便可以通过 g.user 获取用户。
响应
Flask在调用视图函数后,会将其返回值作为相应内容。多数情况下,响应就是返回一个HTML页面或者JSON数据。
HTTP协议中不仅仅要有请求响应的字符串,还有一个部分叫做状态码,这个在HTTP协议快速了解章节中提到过。Flask默认正常情况下的状态码是200,表明请求已经被正确的处理。
如果视图函数需要返回一个指定的状态码,那么在字符串后方,加入加入第二个参数。将返回码作为第二个参数返回到页面上。
当然你也可以添加第三个参数,在这里返回你自定义的响应首部,也就是响应头。
1 | @app.route('/return_code') |
如果不想每次都在return后面接上这些参数组成的远足你也可以使用Flask视图函数提供的make_response()
函数,将上述的三个参数传入进这个函数,等效于我们直接在return后面写。
1 | from flask import make_response |
常见的响应对象如下表格。
属性或方法 | 说明 |
---|---|
status_code | HTTP数字状态码 |
headers | 包含随响应发送的所有首部 |
content_length | 响应主体的长度 |
set_data() | 使用字符串或字节值设定响应 |
set_cookie() | 为响应添加一个cookie |
delete_cookie() | 删除一个cookie |
重定向
有一个特殊的响应叫重定向,这种响应没有页面,但是会告诉浏览器一个新的URL,用来加载新页面。重定向的HTTP状态码通常是302。
可以通过redirect()函数来返回重定向响应。
1 | from flask import redirect |
你也可以自己定义重定向,不过既然已经有提供好的函数就不要使用自定义重定向的方式了。
1 | response.status_code=302 |
返回错误
还有一种特殊的响应由 abort() 函数生成,用于处理错误。下面这里例子中,如果user路径后方参数不是root,那么会返回HTTP500状态码(服务器内部错误)。
1 | from flask import abort |
注意abort()
的参数必须是异常的状态码。服务器会根据错误码自动生成错误描述。而且一旦使用了abort()
那么控制权就不会是调用它的函数了,它会直接抛出相应的异常。