欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flask - request、response - 请求、响应

程序员文章站 2022-06-01 22:56:43
...

目录

一、request 请求相关属性

二、 response、后台return的数据形式

2-1 基于return方式 生成的response对象 的修改操作

三、request 请求扩展

3-1 @before_request - 收到请求前执行绑定函数

3-2 @after_request - 每个请求后执行绑定函数,若请求异常不执行

3-3 @before_first_request - 第一次请求时触发函数执行

3-4 @teardown_request - 每个请求后执行绑定函数,若请求异常照常执行

3-5 @errorhandler - 根据错误状态码自定义返回

3-6 @template_global - 模板的标签使用

3-7 @template_filter - 模板过滤器使用

四、中间件

4-1 中间件实现方式

4-2 源码分析

五、请求上下文源码分析 - 请求流程解析


一、request 请求相关属性

  • request.method  - 请求的方式
  • request.args  - get方式提交的数据,即URL内包含的数据信息
    • request.args.get('key', )
  • request.form  - Post方式提交的数据,字典形式存储获取
  • request.values - CombinedMultiDict 字典形式存储,内容是formargs。 可以使用values替代form和args。
  • request.cookies  - 请求的cookies,类型是dict
  • request.stream - 在可知的mimetype下,如果进来的表单数据无法解码,会没有任何改动的保存到这个·stream·以供使用。很多时候,当请求的数据转换为string时,使用data是最好的方式。这个stream只返回数据一次。
  • request.headers - 请求头,字典形式,结果以list形式返回
  • request.data - 包含了请求的数据,并转换为字符串,除非是一个Flask无法处理的mimetype。
  • 用户请求路径获取方式(例如 :http://www.example.com/myapplication/page.html?x=y )
  • request.files - MultiDict,带有通过POST或PUT请求上传的文件。
    • obj = request.files['the_file_name']
      obj.save('/var/www/uploads/' + secure_filename(f.filename))

       

  • request.environ - WSGI隐含的环境配置。
  • request.is_xhr  - 如果请求是发送到一个实际的模块,则该参数返回当前模块的名称。这是弃用的功能,使用blueprints替代。
  • request.blueprint  - 蓝图名字
  • request.endpoint - endpoint匹配请求,这个与view_args相结合,可是用于重构相同或修改URL。当匹配的时候发生异常,会返回None。
  • request.json - 如果mimetypeapplication/json,这个参数将会解析JSON数据,如果不是则返回None。 
    可以使用这个替代get_json()方法。
  • request.max_content_length - 只读,返回MAX_CONTENT_LENGTH的配置键。
  • request.module  - 如果请求是发送到一个实际的模块,则该参数返回当前模块的名称。这是弃用的功能,使用blueprints替代。

1-1 基于 request 的 ip 获取

Python Flask使用Nginx做代理时如何获取真实IP

Nginx反向代理 + Flask + gunicorn 架构解决获取用户真实ip问题

request.headers.get('REMOTE_ADDR')
request.headers.get('HTTP_X_FORWARDED_FOR')
request.remote_addr
request.environ.get('REMOTE_ADDR')
request.environ.get('HTTP_X_FORWARDED_FOR')

Flask - request、response - 请求、响应

Flask - request、response - 请求、响应

二、 response、后台return的数据形式

  • return "字符串" - 字符串形式
  • return render_template('html模板路径',**{}) - 将数据递交给指定模板
  • return redirect('/index.html') - 重定向页面
  • return jsonify({'k1':'v1'}) - 返回json数据

2-1 基于return方式 生成的response对象 的修改操作

from flask import make_response,jsonify

# 生成response对象,用于往内进行添加操作 - 三种实现方式
# response是flask.wrappers.Response类型
response = make_response("字符串")
response = make_response(render_template('index.html'))
response = make_response(redirect('/index.html'))
response = make_response(jsonify({'k1':'v1'}))

# 对response进行cookie操作,删除写入cookie值
response.delete_cookie('key')
response.set_cookie('key', 'value')
response.headers['X-Something'] = 'A value'

return response

三、request 请求扩展

!!注意点总结!!

  • 执行流程
    • @before_request 包裹函数1,函数2
    • 请求的执行
    • @after_request 包裹函数2,函数1
  • 若 @before_request 或者@after_request 包裹函数内存在return返回值,之后其他被 after_request包裹的函数照常执行。

3-1 @before_request - 收到请求前执行绑定函数

类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情

# 基于before_request的用户登录认证
@app.before_request
def process_request(*args,**kwargs):
    if request.path == '/login':
        return None
    user = session.get('user_info')
    if user:
        return None
    return redirect('/login')

3-2 @after_request - 每个请求后执行绑定函数,若请求异常不执行

类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常

@app.after_request
def process_response1(response):
    print('process_response1 执行')
    return response

3-3 @before_first_request - 第一次请求时触发函数执行

@app.before_first_request
def first():
    pass

3-4 @teardown_request - 每个请求后执行绑定函数,若请求异常照常执行

@app.teardown_request 
def ter(e):
    pass

3-5 @errorhandler - 根据错误状态码自定义返回

路径不存在时404,服务器内部错误500

@app.errorhandler(404)
def error_404(arg):
    return "404错误了"

3-6 @template_global - 模板的标签使用

@app.template_global()
def sb(a1, a2):
    return a1 + a2
#{{sb(1,2)}}

3-7 @template_filter - 模板过滤器使用

@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3
#{{ 1|db(2,3)}}

四、中间件

4-1 中间件实现方式

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World!'

# 模拟中间件
class Md(object):
    def __init__(self,old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app

    def __call__(self,  environ, start_response):
        print('开始之前')
        ret = self.old_wsgi_app(environ, start_response)
        print('结束之后')
        return ret

if __name__ == '__main__':
    # 将原wsgi_app作为参数传入,即替换操作
    app.wsgi_app = Md(app.wsgi_app)
    app.run()

4-2 源码分析

每次执行Flask对象时,本质上是调用了对象的__call__方法。

Flask - request、response - 请求、响应

即,在__call__方法return前执行的逻辑为请求未开始前最开始的部位,return后执行的逻辑为最末尾的执行。

所以中间件的实现方式,重写Flask对象的__call__方法,将前后逻辑包裹在 wsgi_app(environ, start_response) 的执行前后。

Flask - request、response - 请求、响应

五、请求上下文源码分析 - 请求流程解析

程序运行,两个LocalStack()对象,一个里面放request和session,另一个放g和current_app

'''第一阶段:将ctx(request,session)放到Local对象上'''

'''第二阶段:视图函数导入:request/session'''
request.method
    -LocalProxy对象.method,执行getattr方法,getattr(self._get_current_object(), name)
        -self._get_current_object()返回return self.__local(),self.__local(),在LocakProxy实例化的时候,object.__setattr__(self, '_LocalProxy__local', local),此处local就是:partial(_lookup_req_object, 'request')

    -def _lookup_req_object(name):
        top = _request_ctx_stack.top #_request_ctx_stack 就是LocalStack()对象,top方法把ctx取出来
        if top is None:
            raise RuntimeError(_request_ctx_err_msg)
        return getattr(top, name)#获取ctx中的request或session对象

'''第三阶段:请求处理完毕'''
    - 获取session并保存到cookie
    - 将ctx删除