【问题标题】:Two decorators produce a conflict两个装饰器产生冲突
【发布时间】:2018-10-05 07:53:56
【问题描述】:

我需要同时使用两个装饰器,但它们相互冲突。这是我的路线:

channel_args = {
    'name': fields.Str(required=True),
    'description': fields.Str(required=False, missing=None, default=None)
}
class ChannelListRoutes(Resource):

    @require_oauth
    @use_args(channel_args, locations=['json'])
    def post(self, args):
        channel = Channel()
        channel.name = args['name']
        channel.description = args['description']
        channel.user_id = current_token.user.id
        db.session.commit()
        db.session.flush()
        return ChannelJson(channel).to_json(), status.HTTP_201_CREATED

require_oauth = ResourceProtector() 来自 Authlib@use_args 使用 webargs 库。
我通过 cURL 发送数据:

curl -H "Authorization: Bearer {access_token}" -H "Content-Type: application/json" -X POST -d "{\"name\":\"Pets\"}" http://127.0.0.1:5000/api/channels

请求后我的应用程序崩溃了:

Traceback (most recent call last):
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask_restful/__init__.py", line 273, in error_router
    return original_handler(e)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/_compat.py", line 34, in reraise
    raise value.with_traceback(tb)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask_restful/__init__.py", line 273, in error_router
    return original_handler(e)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/_compat.py", line 34, in reraise
    raise value.with_traceback(tb)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask_restful/__init__.py", line 484, in wrapper
    return self.make_response(data, code, headers=headers)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask_restful/__init__.py", line 513, in make_response
    resp = self.representations[mediatype](data, *args, **kwargs)
  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/flask_restful/representations/json.py", line 21, in output_json
    dumped = dumps(data, **settings) + "\n"
  File "/usr/lib/python3.6/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/lib/python3.6/json/encoder.py", line 201, in encode
    chunks = list(chunks)
  File "/usr/lib/python3.6/json/encoder.py", line 437, in _iterencode
    o = _default(o)
  File "/usr/lib/python3.6/json/encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'function' is not JSON serializable

P.S.我试图改变装饰器的顺序,它也没有帮助,虽然它产生了一个新的堆栈跟踪:

  File "/home/ghostman/Projects/vistory/auth/venv/lib/python3.6/site-packages/webargs/core.py", line 482, in wrapper
    return func(*new_args, **kwargs)
TypeError: wrapper() takes 1 positional argument but 2 were given

【问题讨论】:

标签: python python-decorators flask-restful authlib webargs


【解决方案1】:

reading the doc might help..require_oauth 需要一个“范围”参数,所以正确的语法是

@require_oauth(scope)
@use_args(channel_args, locations=['json'])
def post(self, args):
    # ...

您还可以通过显式传递None (@require_oauth(None)) 或通过不带任何参数调用require_oauth 隐式传递来避免指定范围,但是您仍然需要调用装饰器,即:

@require_oauth()
@use_args(channel_args, locations=['json'])
def post(self, args):
    # ...

=> 注意括号(python 中的调用运算符)。

【讨论】:

  • 我在没有范围的其他路线中使用它,我的服务完全没有范围。您可以传递参数,但它不需要。
  • 这就是文档中所写的内容,并且与您遇到的错误相符。
  • this。我说不需要,只能接受。我有一个不使用范围的 Authlib 真实项目。
  • @Шах 您的链接已损坏,但如果您在最后添加缺少的“.html”,您最终也会进入我链接的确切页面,所有字母都解释说“如果资源是不受范围保护,使用无”。它还提供了一个示例,其中 None 未显式传递(IOW 它是 scope 的默认值),但您仍然需要调用装饰器。
  • 请仔细阅读我的答案(和文档):您需要致电装饰者
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多