我在项目中使用django-revproxy和Django REST Framework。我公开了一个API,用户可以在其中获取有关其聊天机器人的分析,其工作原理如下:
if True
它与另一个外部服务联系。我的 urls.py :
# urls.py
urlpatterns = (
url(r'^analytics/(?P<path>.*)$', api.AnalyticsFunctionsProxyView.as_view()),
)
在我看来:
# views.py
from rest_framework.authentication import TokenAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from revproxy.views import ProxyView
from .permissions import HasChatBotPermission
...
class AnalyticsFunctionsProxyView(ProxyView):
upstream = settings.ANALYTICS_FAAS_URL
def parse_body(self, request):
if isinstance(request, rest_framework.request.Request):
return request.data
return super(AnalyticsFunctionsProxyView, self).parse_body(request)
@classmethod
def as_view(cls, *args, **kwargs):
view = super(AnalyticsFunctionsProxyView, cls).as_view(*args, **kwargs)
view = permission_classes((IsAuthenticated, HasChatBotPermission,))(view)
view = authentication_classes([TokenAuthentication, JSONWebTokenAuthentication])(view)
view = api_view(['GET', 'POST'])(view)
return view
我的HasChatBotPermission
权限
#permissions.py
class HasChatBotPermission(permissions.BasePermission):
def has_permission(self, request, view):
try:
bot_name = request.data.get('name')
user = request.user
self.message = 'Permission denied for {}'.format(name)
return ChatBot.objects.filter(user=user, project_name=project_id).exists()
except Exception:
self.message = 'Permission denied, no project_id was defined!'
return False
调用视图时会引发以下异常:
Traceback (most recent call last):
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/rest_framework/request.py", line 379, 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 "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 42, in inner
response = get_response(request)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/fcmam5/anaconda3/lib/python3.6/contextlib.py", line 52, in inner
return func(*args, **kwds)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
return view_func(*args, **kwargs)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/rest_framework/views.py", line 477, in dispatch
response = self.handle_exception(exc)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/rest_framework/views.py", line 437, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/rest_framework/views.py", line 474, in dispatch
response = handler(request, *args, **kwargs)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/rest_framework/decorators.py", line 52, in handler
return func(*args, **kwargs)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/revproxy/views.py", line 204, in dispatch
proxy_response = self._created_proxy_response(request, path)
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/revproxy/views.py", line 139, in _created_proxy_response
request_payload = request.body
File "/home/fcmam5/dela3a/env/lib/python3.6/site-packages/rest_framework/request.py", line 383, in __getattribute__
return getattr(self._request, attr)
File "/home/fcmam5/dela3a/env/lib/python3.6/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
问题是由我的bot_name = request.data.get('name')
中的这一行permissions.py
引起的,当我直接传递字符串时,它顺利通过了。
我的问题是:
这是我在Stackoverflow中的第一个问题,对不起,如果我的问题不是英语,并且对我的英语不好:)
答案 0 :(得分:1)
您遇到此错误是因为django-revproxy
试图读取原始请求正文,以便它可以创建到上游服务器的代理请求。
但是,使用Django(以及WSGI和缓冲)语义,一旦您以但原始流的形式访问请求正文,就无法实现此目的,{{{ 1}}。根据DRF的请求协商配置,此操作会将请求正文解析为JSON,HTTP multipart等,并使用流。
据我所知,有两种解决方法:
request.data.get('name')
传递到身体以外的其他地方;例如查询字符串参数,HTTP标头,URL的一部分,因此您无需访问正文,或者bot_name
而不是反向代理来进行后端请求(这基本上是同一件事,但是增加了尝试按原样复制请求的功能)。