2017-08-10 29 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) 
相關問題