0%

Flask源码之Request对象(六)

引言

我们知道

1
from flask import request

是一个代理对象,实际上代理的是 RequestContextrequest属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class RequestContext(object):

def __init__(self, app, environ, request=None, session=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = None
try:
self.url_adapter = app.create_url_adapter(self.request)
except HTTPException as e:
self.request.routing_exception = e
self.flashes = None
self.session = session

那么request属性又是什么什么呢?

原理与实现

1
request = app.request_class(environ)

request_class定义如下

image-20210106233013649

从上面代码可以看出来,requestrequest_class的实例,request_class是一个Request

定义在flaskwrappers.py

1
class Request(RequestBase, JSONMixin):

mixinpython多继承的方式,从面向对象的语义来看,表达的是 has关系而不是 is关系,用于为子类提供一些额外的方法

相当于javainterface

我们知道我们用的request实际上是这个Request的实例就好了

继承关系

image-20210106235017437

我们重点看一下 JSONMixin的实现

flask.wrappers.JSONMixin

1
2
3
4
5
6
7
8
class JSONMixin(_JSONMixin):
json_module = json

def on_json_loading_failed(self, e):
if current_app and current_app.debug:
raise BadRequest("Failed to decode JSON object: {0}".format(e))

raise BadRequest()

有一个 on_json_loading_failed方法,他的作用是什么呢

on_json_loading_failed

作用

我们知道前后端以json方式交互,对于前端传过来的数据我们要load成字典,json.load(environ中前端传过来的json数据)

那么失败了就会调用这个函数

我们可以 继承Request,写一个自定义的对象,重写这个方法,并赋值给Flask

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from flask import Flask, jsonify, Request
from werkzeug.exceptions import BadRequest

flask_app = Flask(__name__)

class MyRequest(Request):
def on_json_loading_failed(self, e):
raise BadRequest("我是自己写的错误描述")


flask_app.request_class = MyRequest


@flask_app.route('/', endpoint="11", methods=["GET", "POST"])
def hello_world():
return jsonify(code=0, msg="success")


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

这样,当load失败后我们就可以自己决定该怎么办

值得注意的是,默认情况下,json.load失败了会raise BadRequest,结合flask中的异常处理方式,我们也可以把他用 errorhandler处理,例如@flask_app.errorhandler(BadRequest)

_JSONMixin

按两下 shift搜索这个父类 _JSONMixin,注意他是被重命名了,我们要搜索 JSONMixin,只不过位置在 werkzeug

定义在 werkzeug

image-20210106234345164

我们看到这个类有个一json方法用于获取前端的json数据。根据继承关系,我们可以

1
2
from flask import request
json_data=request.json()

json_module

此外我们还看到两个 JSONMixin都有 json_module属性,属性值json对象,这个json是什么?是标准库的json吗???

1
2
3
4
5
6
7
8
class JSONMixin(_JSONMixin):
json_module = json

def on_json_loading_failed(self, e):
if current_app and current_app.debug:
raise BadRequest("Failed to decode JSON object: {0}".format(e))

raise BadRequest()

查看 json 源码知道,这里json_module属性的作用是指定了序列化反序列化的模块,这个json不是标准库的,而是自定义的

位置在 flask.json

image-20210106235551849

我们很容易在其中找到loads等方法,注意到其中的_json就是标准库的json库,所以他是对标准库json的封装

当然,我们也可以用自己的json模块

例如你想不开想使用pickle(跑路吧)

1
2
3
4
class MyRequest(Request):
json_module=pickle
def on_json_loading_failed(self, e):
raise BadRequest()

参考文章

flask-insight-request