一般来说, 现在的python应用服务器遵从wsgi协议, flask的app获取gunicorn的environ, start_response参数, 然后处理, 抓包gunicorn发过来的environ数据如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'HTTP_ACCEPT_ENCODING': 'gzip, deflate',
'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'HTTP_CACHE_CONTROL': 'max-age=0',
'HTTP_CONNECTION': 'keep-alive',
'HTTP_COOKIE': 'session=.eJxdy0kKgCAUANC7_LUECuaw6iby018JTjRAFN291q0f7wYXA1iQSML0QaLyOhjuhZaj0ooDA9dozVio7GD39SAGlDEmF8tUv5nitVCZh0TnQZ2v-SsNt-3',
'HTTP_DNT': '1',
'HTTP_HOST': '0.0.0.0:3000',
'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
'HTTP_USER_AGENT': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'PATH_INFO': '/',
'QUERY_STRING': '',
'RAW_URI': '/',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '59734',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': '0.0.0.0',
'SERVER_PORT': '3000',
'SERVER_PROTOCOL': 'HTTP/1.1',
'SERVER_SOFTWARE': 'gunicorn/19.9.0',
'gunicorn.socket': <socket.socket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 3000), raddr=('127.0.0.1', 59734)>,
'wsgi.errors': <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fa5719707f0>,
'wsgi.file_wrapper': <class 'gunicorn.http.wsgi.FileWrapper'>,
'wsgi.input': <gunicorn.http.body.Body object at 0x7fa5719707b8>,
'wsgi.multiprocess': False,
'wsgi.multithread': False,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)
}

在flask中, 想获取前端的数据大概有三种方式, 在Request类中有描述:

  • request.args()
    • url中query部分字段
  • request.form()
  • request.data
  • request.json()

request.args

这个方法主要获取请求url中的query字段, 在flask的Request.args方法中提取environ的QUERY_STRING字段进行解析, 具体实现位于werkzeug.wrappers.base_request/BaseRequest中.

request.form

这个字段获取form表单的数据, 一般来说, http通过post或者put方法发送form数据, 然后定义Content-Type字段决定如何解析form数据:

application/x-www-form-urlencoded

数据被编码成以&分隔的键值对, 同时以 ‘=’ 分隔键和值. 非字母或数字的字符会被 percent-encoding: 这也就是为什么这种类型不支持二进制数据的原因 (应使用 multipart/form-data 代替).

1
2
3
4
5
6
POST / HTTP/1.1
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

say=Hi&to=Mom

multipart/form-data

一般上如果长传文件或者大的数据的话用这种方法, 因为上面的方法会对不安全的字符进行编码,

1
2
3
4
5
6
7
8
9
10
11
12
POST /test.html HTTP/1.1 
Host: example.org
Content-Type: multipart/form-data;boundary="boundary"

--boundary # 这个值单词就是上面的value
Content-Disposition: form-data; name="field1"

value1
--boundary
Content-Disposition: form-data; name="field2"; filename="example.txt"

value2

flask解析的实现

flask对form数据的解析是在werkzeug.formparser.FormDataParser中实现的, 对不同的Content-Type提供不同的解析方法:

1
2
3
4
5
parse_functions = {
"multipart/form-data": _parse_multipart,
"application/x-www-form-urlencoded": _parse_urlencoded,
"application/x-url-encoded": _parse_urlencoded,
}

request.json()

现在一般都用json做前后端交互的格式, 看下lfaks的json解析过程, flask的json解析存在于JSONMixin.get_json()这个方法中, 先调用is_json查询mimetype是不是application/.*json, 如果是, 那么获取请求的data然后尝试调用json.loads方法解析数据成json格式, 如果不是, 直接返回None.