文章目录
- 一、请求响应循环
- 二、HTTP请求
- 1. 请求报文
- 2. request对象
- 3. 在flask中处理请求
- 3.1 路由匹配
- 3.2 设置监听的http方法
- 3.3 URL处理
- 三、请求钩子
一、请求响应循环
每一个web应用都包含这种处理方式,请求-响应循环:客户端发出请求,服务器端接受请求并返回响应。
从下图可以看出,HTTP在整个流程中起到了至关重要的作用,它是客户端和服务器端之间沟通的桥梁。
当用户访问一个URL,浏览器便生成对应的HTTP请求,经由互联网发送到对应的Web服务器。Web服务器接收请求,通过WSGI将HTTP格式的请求数据转换成我们的Flask程序能够使用的Python数据。在程序中,Flask根据请求的URL执行对应的视图函数,获取返回值生成响应。响应依次经过WSGI转换生成HTTP响应,再经由Web服务器传递,最终被发出请求的客户端接收。浏览器渲染响应中包含的HTML和CSS代码,并执行JavaScript代码,最终把解析后的页面呈现在用户浏览器的窗口中
二、HTTP请求
URL是一个请求的起源。一个标准的URL由很多部分组成,以下面这个为例:
http://www.baidu.com/hello?name=zly
http::协议字符串,指定要使用的协议。
www.baidu.com:服务器弟子(域名)。
/hello?name=zly:要获取的资源路径(path),类似于unix的文件目录结构。
请求的实质是发送到服务器上的一些数据,这种浏览器与服务器之间交互的数据称为报文,请求时浏览器发送的数据被称为请求报文,而服务器返回的数据被称为响应报文。
1. 请求报文
请求报文由请求的方法、URL、协议版本、首部字段以及内容实体组成。
常见的http方法类型:
方法 | 说明 |
---|---|
get | 获取资源 |
post | 创建或更新资源 |
put | 创建或替换资源 |
delete | 删除资源 |
head | 获得报文首部 |
options | 询问支持的方法 |
报文首部包含了请求的各种信息和设置,比如客户端的类型,是否设置缓存,语言偏好等等。
2. request对象
flask请求对象request,这个请求对象封装了从客户端发来的请求报文。
请求解析和响应封装实际上大部分是由werkzeug完成的,flask子类化werkzeug的请求(Request)和响应(Response)对象并添加了和程序相关的特定功能。
假如此时有一个请求http://www.baidu.com.cn/hello?name=zly
当flask接收到请求后,请求对象会提供多个属性来获取URL的各个部分。常用属性如下表所示:
属性 | 值 |
---|---|
path | ‘/hello’ |
full_path | ‘/hello?=name=zly’ |
host | ‘www.baidu.com.cn’ |
host_url | ‘http://www.baidu.com.cn/’ |
base_url | ‘http://www.baidu.com.cn/hello’ |
url | ‘http://www.baidu.com.cn/hello?name=zly’ |
url_root | ‘http://www.baidu.com.cn/’ |
除了URL之外,请求报文中的其他信息都可以通过Request对象提供的属性和方法获取,常用部分如下表所示:
属性/方法 | 说明 |
---|---|
method | 获取请求的HTTP方法,例如GET、POST、PUT等。 |
args | 包含GET请求参数的字典,可以通过request.args[‘key’]或request.args.get(‘key’)来获取特定参数的值。 |
form | 包含POST请求参数的字典,可以通过request.form[‘key’]或request.form.get(‘key’)来获取特定参数的值。 |
files | 包含上传文件的字典,可以使用request.files[‘file_field_name’]来访问上传的文件。 |
headers | 获取请求头部信息,返回一个包含所有请求头的字典。可以使用request.headers[‘header_name’]来获取特定头部的值。 |
cookies | 包含所有的Cookie信息的字典,可以使用request.cookies[‘cookie_name’]来获取特定Cookie的值。 |
session | 访问当前用户的会话对象,可以使用request.session[‘key’]来获取会话数据。 |
3. 在flask中处理请求
url是指向网络上资源的地址。在flask中,我们需要让请求的URL匹配对应的视图函数,视图函数返回值就是URL对应的资源。
3.1 路由匹配
在 Flask 中,路由匹配是通过装饰器来完成的。你可以使用 @app.route 装饰器来定义路由,并指定对应的 URL 规则。
from flask import Flask
app = Flask(__name__)
# 定义根路径的路由
@app.route('/')
def index():
return 'Hello, World!'
# 定义其他路径的路由
@app.route('/about')
def about():
return 'About page'
@app.route('/user/<username>')
def user_profile(username):
return f'Profile page of {username}'
3.2 设置监听的http方法
在 Flask 中,你可以使用 methods 参数来设置路由监听的 HTTP 方法。这个参数可以是一个字符串,也可以是一个包含多个方法的列表。
from flask import Flask, request
app = Flask(__name__)
# 设置只接受 GET 请求的路由
@app.route('/', methods=['GET'])
def index():
return 'Hello, World!'
# 设置接受 POST 和 PUT 请求的路由
@app.route('/data', methods=['POST', 'PUT'])
def handle_data():
if request.method == 'POST':
return 'Received a POST request'
elif request.method == 'PUT':
return 'Received a PUT request'
3.3 URL处理
URL变量部分默认类型为字符串,但flask提供了一些转换器可以在URL规则中使用。
转换器 | 说明 |
---|---|
string | 不包含斜线的字符串 |
int | 整数 |
float | 浮点数 |
path | 包含斜线的字符串,static路由的URL规则中filename变量就使用了这个转换器 |
any | 匹配一系列值中的一个 |
uuid | uuid字符串 |
使用示例:
@app.route('/goback/<int:year>')
def go_back(year):
return '<p>Welcome to %d!</p> ' % (2018-year)
@app.route('/colors/<any(blue, white, red):color>')
def three_colors(color):
return color
三、请求钩子
在 Flask 中,你可以使用请求钩子(Request Hooks)来在请求的不同生命周期中执行特定的操作。Flask 提供了一些装饰器来定义这些钩子函数。
以下是几个常用的请求钩子:
- before_request:在每个请求处理之前执行。可以用于进行认证、权限检查等操作。例如网站要记录用户最后在线的时间,可通过用户最后发送的请求时间来实现。
- after_request:在每个请求处理之后执行,但只有在没有未处理的异常时才会执行。可以用于修改响应、添加头部信息等操作。例如我们经常在视图函数中进行数据库操作,比如更新、插入等,之后需要将更改提交数据库中,提交更改的代码可以放到此钩子中。
- teardown_request:在每个请求处理之后执行,无论是否发生异常。可以用于清理资源、关闭数据库连接等操作。
- before_first_request:在第一个请求处理之前执行,用于初始化应用程序的全局状态。例如在玩具程序中,运行程序前我们需要进行一些程序的初始化操作,比如创建数据库表,添加管理员用户。
from flask import Flask
app = Flask(__name__)
# 在每个请求处理之前执行的钩子
@app.before_request
def before_request():
# 在这里执行需要在每个请求之前进行的操作
print('Before Request')
# 在每个请求处理之后执行的钩子
@app.after_request
def after_request(response):
# 在这里执行需要在每个请求之后进行的操作
print('After Request')
return response
# 在每个请求处理之后(包括异常情况)执行的钩子
@app.teardown_request
def teardown_request(exception=None):
# 在这里执行需要在每个请求之后进行的操作
print('Teardown Request')
# 在第一个请求处理之前执行的钩子
@app.before_first_request
def before_first_request():
# 在这里执行需要在第一个请求之前进行的操作
print('Before First Request')
# 定义路由
@app.route('/')
def index():
return 'Hello, World!'
if __name__ == '__main__':
app.run()