简体   繁体   English

flask-restful - 当前请求的资源类

[英]flask-restful - resource class for current request

THE QUESTION 问题

All of my app's routes are defined via flask-restful Resources. 我所有应用程序的路由都是通过flask-restful Resources定义的。 How can I find the resource object/class that is processing current request? 如何找到处理当前请求的资源对象/类?

WHY I WANT THIS 为什么我想要这个

I wanted to log all exceptions raised while processing requests. 我想记录处理请求时引发的所有异常。 I connect to flask.got_request_exception , as described in http://flask.pocoo.org/docs/1.0/api/#signals and something like this works well: 我连接到flask.got_request_exception ,如http://flask.pocoo.org/docs/1.0/api/#signals中所述,这样的效果很好:

from flask import got_request_exception, request

def log_exception(sender, exception, **extra):
    logger.info("URL: {}, Exception: {}".format(request.url, type(exception).__name__))

got_request_exception.connect(log_exception, app)

The only problem is that I want to log some of the request data, but not all the data - eg I'd like to hide passwords. 唯一的问题是我想记录一些请求数据,但不是所有数据 - 例如我想隐藏密码。 I think it would be a good idea to have logging-data-logic together with request processing logic, like this: 我认为将日志记录数据逻辑与请求处理逻辑结合在一起是个好主意,如下所示:

from flask import request
import flask_restful

class SomeResource(flask_restful.Resource):
    def get(self):
        # ... GET processing
    def log_data(self):
        # log all body params
        return request.get_json()

class Login(flask_restful.Resource):
   def post(self):
       # ... authentication
   def log_data(self):
       # log selected body params
       return {'login': request.get_json()['login'], 'password': 'HIDDEN!'}

and than use it in my log_exception : 而不是在我的log_exception使用它:

from flask import got_request_exception, request

def log_exception(sender, exception, **extra):
    resource_class = # THIS IS THE THING I'M MISSING
    logger.info("URL: {}, Exception: {}, Data: {}".format(request.url, type(exception).__name__), 
                resource_class.log_data())

got_request_exception.connect(log_exception, app) 

But maybe this should be done other way? 但也许这应该以其他方式完成?

Instead of inheriting from flask_restful.Resource your want to inherit all from a custom resource 您希望从自定义资源继承所有内容,而不是继承flask_restful.Resource

class MyResource(flask_restful.Resource):
    def dispatch_request(self, *args, **kwargs):
        try:
            return super(MyResource,self).dispatch_request(*args, **kwargs)
        except Exception as ex:
            setattr(ex, "_raised_by", self)
            raise ex

and then you can use the exception handler 然后你可以使用异常处理程序

def log_exception(sender, exception, **extra):
    _raised_by = getattr(exception, "_raised_by", None)
    if _raised_by:
        print(_raised_by)
    property("URL: {}, Exception: {}".format(request.url, type(exception).__name__))

Here is complete code I tried 这是我试过的完整代码

from flask import request, Flask
import flask_restful

app = Flask(__name__)

api = flask_restful.Api(app)


class MyResource(flask_restful.Resource):
    def dispatch_request(self, *args, **kwargs):
        try:
            return super(MyResource,self).dispatch_request(*args, **kwargs)
        except Exception as ex:
            setattr(ex, "_raised_by", self)
            raise ex

# MyResource = flask_restful.Resource

class SomeResource(MyResource):
    def get(self):
        raise Exception("Not implemented")

    def log_data(self):
        # log all body params
        return request.get_json()


class Login(MyResource):
    def post(self):
        raise Exception("Not implemented")

    def log_data(self):
        # log selected body params
        return {'login': request.get_json()['login'], 'password': 'HIDDEN!'}


from flask import got_request_exception, request

api.add_resource(Login, '/login')
api.add_resource(SomeResource, '/some')


def log_exception(sender, exception, **extra):
    _raised_by = getattr(exception, "_raised_by", None)
    if _raised_by:
        print(_raised_by)
    property("URL: {}, Exception: {}".format(request.url, type(exception).__name__))


got_request_exception.connect(log_exception, app)

if __name__ == '__main__':
    app.run(debug=True)

Edit-1: 5th Aug 编辑1:8月5日

As commented by @jbet, in case one wants to get the processing class always a cleaner option would be to use the MyResource as below 正如@jbet评论的那样,如果想要获得处理类总是一个更清晰的选项,那就是使用MyResource ,如下所示

from flask import g

class MyResource(flask_restful.Resource):
    def dispatch_request(self, *args, **kwargs):
        g.processed_by = self
        return super(MyResource,self).dispatch_request(*args, **kwargs)

I could not find a nice way to get access to your object once the logging method had been called by signals. 一旦通过信号调用了日志记录方法,我找不到一种很好的方式来访问您的对象。

If you were willing to handle all possible cases, you could create your own custom exceptions that call the log_data method on your class. 如果您愿意处理所有可能的情况,您可以创建自己的自定义异常,在您的类上调用log_data方法。

Instead, I opted to handle logging myself in a base class. 相反,我选择在基类中处理自己的日志。 Simple example for you, I just used print functions, but you could call app.logging.info instead. 简单的例子,我刚刚使用了打印功能,但你可以调用app.logging.info。

from flask import Flask, request
import flask_restful

app = Flask(__name__)
api = flask_restful.Api(app)

class MyCustomResource(flask_restful.Resource):
    def get(self):
        try:
            self.my_get()
        except Exception as exception:
            # Will catch all errors in your subclass my_get method
            print("exception caught")
            print(request.url)
            print(type(exception).__name__)
            print(self.log_data())

            # Re-raise if you want (or not)
            raise exception

    def my_get(self):
        # Python equivalent of virtual method
        raise NotImplementedError()

    def log_data(self):
        # Python equivalent of virtual method
        raise NotImplementedError()


class SomeResource(MyCustomResource):
    def my_get(self):
        # Example unknown error occurs here
        raise Exception("error!")
        return "some data"

    def log_data(self):
        # Called by parent
        return "some logging data for the object"

api.add_resource(SomeResource, "/")

If you wanted to dig deeper into the flask restful source you could also monkey patch (or build your own package) whatever method is calling get/post. 如果你想更深入地了解烧瓶的源代码,你也可以使用任何方法调用get / post来修补补丁(或构建自己的包)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM