【问题标题】:Flask Middleware with both Request and Response具有请求和响应的 Flask 中间件
【发布时间】:2021-10-04 15:35:03
【问题描述】:

我想在 Flask 中创建一个中间件函数,用于记录来自请求响应的详细信息。中间件应该在创建响应之后但在它被发回之前运行。我要登录:

  1. 请求的 HTTP 方法(GETPOSTPUT
  2. 请求端点
  3. 响应 HTTP 状态代码,包括 500 个响应。因此,如果在视图函数中引发异常,我想在 Flask 内部发送它之前记录生成的 500 响应。

我发现的一些选项(对我来说不太适用):

  1. before_requestafter_request 装饰器。如果我可以访问after_request中的请求数据,我的问题仍然无法解决,因为根据文档

如果函数引发异常,则不会调用任何剩余的 after_request 函数。

  1. Deferred Request Callbacks - 此页面上描述了一个 after_this_request 装饰器,它装饰任意函数(在当前视图函数中定义)并将其注册为在当前请求之后运行。由于任意函数可以包含来自请求和响应的信息,它部分解决了我的问题。问题是我必须在每个视图函数中添加这样一个装饰函数;我非常想避免这种情况。
@app.route('/')
def index():
    @after_this_request
    def add_header(response):
        response.headers['X-Foo'] = 'Parachute'
        return response
    return 'Hello World!'

有什么建议吗?

【问题讨论】:

    标签: python flask wsgi


    【解决方案1】:

    好的,所以答案一直盯着我的脸,在 Deferred Request Callbacks 的页面上。

    诀窍是使用after_this_requestbefore_request 回调中注册一个函数以在当前请求之后运行。这是对我有用的代码 sn-p:

    @app.before_request
    def log_details():
        method = request.method
        url = request.url
    
        @after_this_request
        def log_details_callback(response: Response):
            logger.info(f'method: {method}\n url: {url}\n status: {response.status}')
    

    这些是步骤:

    1. before_request 回调中的响应中获取所需的详细信息并将它们存储在一些变量中。
    2. 然后在您用after_this_request 装饰的函数中访问您想要的响应,以及您之前存储请求详细信息的变量。

    【讨论】:

      【解决方案2】:

      我的第一个答案很老套。通过在 Flask 中使用g object,实际上有更好的方法来实现相同的结果。它对于在单个请求期间全局存储信息很有用。来自the documentation

      g 名称代表“全局”,但它指的是数据在上下文中是全局的。 g 上的数据在上下文结束后丢失,并且它不是在请求之间存储数据的合适位置。使用会话或数据库跨请求存储数据。

      这就是你将如何使用它:

      @app.before_request
      def gather_request_data():
          g.method = request.method
          g.url = request.url
      
      @app.after_request
      def log_details(response: Response):
          g.status = response.status
      
          logger.info(f'method: {g.method}\n url: {g.url}\n status: {g.status}')
      
          return response
      
      1. 在用@app.before_request 修饰的函数中收集您想要的任何请求信息,并将其存储在g 对象中。
      2. 从用@app.after_request 装饰的函数中的响应中访问您想要的任何内容。您仍然可以参考您在第 1 步中存储在 g 对象中的信息。请注意,您必须在此函数结束时返回响应。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-27
        • 2016-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多