flask-restful - класс ресурсов для текущего запроса - PullRequest
1 голос
/ 18 июня 2019

ВОПРОС

Все маршруты моего приложения определяются с помощью ресурсов, сохраняемых во флаконах.Как найти объект / класс ресурса, который обрабатывает текущий запрос?

ПОЧЕМУ Я ХОЧУ ЭТО

Я хотел записать все исключения, возникшие при обработке запросов.Я подключаюсь к 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)

Единственная проблема заключается в том, что я хочу записать некоторые данные запроса, но не вседанные - например, я хотел бы скрыть пароли.Я думаю, что было бы неплохо иметь логику регистрации данных вместе с логикой обработки запросов, например:

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!'}

и использовать ее в моем 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) 

Но может быть, это нужно сделать по-другому?

Ответы [ 2 ]

1 голос
/ 19 июля 2019

Я не смог найти хороший способ получить доступ к вашему объекту после вызова метода регистрации по сигналам.

Если вы готовы обработать все возможные случаи, вы можете создать свои собственные исключения, которые вызывают метод log_data для вашего класса.

Вместо этого я решил заняться регистрацией самостоятельно в базовом классе. Простой пример для вас, я просто использовал функции печати, но вместо этого вы могли бы вызвать 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, "/")

Если вы хотите глубже покопаться в исходном коде колбы, вы также можете установить патч (или создать свой собственный пакет) для любого метода, вызывающего get / post.

0 голосов
/ 19 июля 2019

Вместо того, чтобы наследовать от 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

и затем вы можете использовать обработчик исключений

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__))

Вот полный код, который я пробовал

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)
...