AWS Elastic Beanstalk工作层可以配置为自动接受单个 AWS SQS队列。此队列上的传入消息可以路由到单个端点,工作层中的某个实例将响应该端点;他们向工作人员展示了POST事件。
我的工作人员运行的软件基于Django / DRF。
我希望我的工作层实例能够处理多种类型的传入事件。理想情况下,SQS可以配置为将请求传递给多个端点,但这似乎是不可能的。
class DispatchSerializer(serializers.Serializer):
"`to` is the name of the destination endpoint; `payload` is the data I want delivered"
to = serializers.CharField(
max_length=80,
)
payload = serializers.JSONField()
@api_view(http_method_names=['POST'])
@permission_classes([AllowAny])
def dispatch(request):
"""
Dispatch a request to a sibling endpoint.
"""
routing_table = {
... # this is specific to my application;
# it's just a dict of names to views
}
serializer = DispatchSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
to = serializer.validated_data['to']
try:
view = routing_table[to]
except KeyError:
raise Http404()
# https://github.com/encode/django-rest-framework/blob/master/rest_framework/request.py#L183-L187
request._full_data = serializer.validated_data['payload']
return view(request)
# If this returns other than 200, SQS simply re-attempts the request later.
# No returned data is preserved, so we might as well not return any.
return Response()
正如您所看到的,我尝试简单地将请求的_full_data
属性替换为有效负载,以便内部视图仅查看用于它的数据(发送视图中的数据是有效负载)。 / p>
此实现实际上不起作用。我收到了这种形式的错误:
Traceback (most recent call last):
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 378, in __getattribute__
return super(Request, self).__getattribute__(attr)
AttributeError: 'Request' object has no attribute 'body'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 378, in __getattribute__
return super(Request, self).__getattribute__(attr)
AttributeError: 'Request' object has no attribute 'body'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/core/handlers/exception.py", line 39, in inner
response = get_response(request)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/decorators.py", line 52, in handler
return func(*args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/project/django-backend/cardamom/worker/views.py", line 196, in dispatch
return view(request)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/views.py", line 483, in dispatch
response = self.handle_exception(exc)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/views.py", line 443, in handle_exception
self.raise_uncaught_exception(exc)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/views.py", line 480, in dispatch
response = handler(request, *args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/decorators.py", line 52, in handler
return func(*args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/project/django-backend/cardamom/core/views/mailchimp.py", line 229, in wrapper
return func(*args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/project/django-backend/cardamom/worker/views.py", line 52, in wrapper
result = f(log_entry, *args, **kwargs)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/project/django-backend/cardamom/worker/views.py", line 106, in match_one
user_id = int(request.data['user_id'])
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 378, in __getattribute__
return super(Request, self).__getattribute__(attr)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 186, in data
self._load_data_and_files()
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 246, in _load_data_and_files
self._data, self._files = self._parse()
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 290, in _parse
stream = self.stream
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 378, in __getattribute__
return super(Request, self).__getattribute__(attr)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 173, in stream
self._load_stream()
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 270, in _load_stream
self._stream = six.BytesIO(self.body)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 382, in __getattribute__
return getattr(self._request, attr)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/rest_framework/request.py", line 382, in __getattribute__
return getattr(self._request, attr)
File "/mnt/d/Users/coriolinus/Documents/Toptal/cardamom/.venv/lib/python3.4/site-packages/django/http/request.py", line 264, in body
raise RawPostDataException("You cannot access body after reading from request's data stream")
django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
request
对象很复杂;产生一个新的是不可信的。同时,我们需要修改此数据,以便将其正确传递到下一个视图,以便该视图仅以预期格式查看数据。
我该如何做到这一点?
我尝试编辑上面的示例以删除对request
对象的任何修改,而是创建了以下序列化程序mixin:
class UndispatcherMixin:
"""
Adjust a serializer such that it can accept its normal serialization,
or alternately the payload of a DispatchSerializer.
"""
def is_valid(self, raise_exception=False):
if not hasattr(self, '_validated_data'):
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
)
ds = DispatchSerializer(data=self.initial_data)
if ds.is_valid(raise_exception=False):
self.initial_data = ds.validated_data['payload']
return super().is_valid(raise_exception=raise_exception)
然后将该mixin添加到下游视图使用的相关序列化器中。有趣的是,它失败了与之前相同的django.http.RawPostDataException
。
只要你传入一个合适的request
对象,你就可以将你的观点称为普通函数。这可能实际上并非如此,至少对于视图是由DRF @api_view
装饰器创建的情况而言。
仍然在努力解决这个问题。
答案 0 :(得分:0)
无论出于何种原因 - 这可能是DRF中的错误,但我不确定 - 您无法从另一个中调用@api_view
函数并传递{ {1}}对象。它只是没有用。
的工作原理是分解执行实际工作的代码,并将其与request
函数以及@api_view
视图分开调用。就是这样:
dispatch