2017-08-10 25 views
4

考虑以下流程:Django中将请求的响应转换为DRF响应的最优雅方式是什么?

public client ----> DRF API on Service A ------> DRF API on Service B 

一些关于服务A的DRF API只是代理到服务B,所以在服务一个特定的API中的是这样的:

class SomeServiceAPI(APIView): 
    def get(request): 
     resp = requests.get('http://service-b.com/api/...') 
     return Response(resp.json()) 

这枚作品在正常状态下,但它有几个问题:

  1. 它不代理服务b的实际状态代码。
  2. 响应中的json序列化的不必要的往返()
  3. 如果服务b返回一个非json错误,服务不会返回来自服务b的实际错误。

问题是,有没有更好的方法来做到这一点?我看了一下Django Rest Framework Proxy项目,但我不完全确定它是否真正适合我的用例。

+0

疯狂的想法,但你可以建立一个响应适配器。将来自请求包的响应调整为DRF响应。 流程是否在两个方向?公众期望B服务的回应,对吗? – Willemoes

+0

不,只是一个方向,总是从A到B. –

回答

2
  1. 您可以通过修改你的Response解决状态代码的一部分:

    return Response(resp.json(), status=resp.status_code) 
    
  2. 对于第二个部分,虽然,这是进行代理的本质......(真,有时要操纵代理中间人的请求和/或响应,但你所做的是本质)。

注:

  • ,你所提出的建议,似乎做的工作只是罚款 ,而不需要你写只是为了 往返特定视图的DRF Proxy
  • 还有另一个工具,DRF Reverse Proxy这是一个DRF端口Django Revproxy,你可能想要考虑。

两个以上的一般想法是,你专门创建一个URL路径代理的路径到另一个API:

DRF代理:

代理添加到settings.py

REST_PROXY = { 
    'HOST': 'http://service-b.com/api/' 
} 

urls.py

url(
    r'^somewere_in_a/$', 
    ProxyView.as_view(source='somewere_in_b/'), 
    name='a_name' 
) 

DRF反向代理:

差不多与上述类似,没有设置的一部分:

url(
    r'^(?P<path>.*)$', 
    ProxyView.as_view(upstream='http://service-b.com/api/somewere_in_b/'), 
    name='a_name' 
) 

意见:DRF Proxy似乎更加坚实...

+0

我已经给DRF Reverse Proxy做了一个快速尝试,但是我无法设法启动并运行它,但仍然非常麻烦。 –

+0

DRF代理似乎只指向一个下游服务,如果稍后我必须代理其他服务,我不会不情愿严重集成它。 –

+0

然后你可以使用你已经实现的传递作为代理@JamesLin –

1

我看了John的回答中提到的两个现有软件包,但他们似乎不太适合我的用例,所以我创建了一个简单的包装来代理这些请求ts'对DRF响应的响应。

# encoding: utf-8 
from __future__ import unicode_literals 
from __future__ import absolute_import 
from rest_framework.response import Response 
from requests.models import Response as RResponse 


class InCompatibleError(Exception): 
    pass 


class DRFResponseWrapper(Response): 
    """ 
    Wraps the requests' response 
    """ 
    def __init__(self, data, *args, **kwargs): 
     if not isinstance(data, RResponse): 
      raise InCompatibleError 

     status = data.status_code 
     content_type = data.headers.get('content_type') 

     try: 
      content = data.json() 
     except: 
      content = data.content 

     super(DRFResponseWrapper, self).__init__(content, status=status, content_type=content_type) 

而使用如下:

resp = requests.get(
     '{}://{}/api/v5/business/'.format(settings.SEARCH_HOST_SCHEMA, settings.SEARCH_HOST), 
     params=request.query_params 
    ) 
    return DRFResponseWrapper(resp) 
相关问题