考虑以下流程:
public client ----> DRF API on Service A ------> DRF API on Service B
服务A上的某些DRF API仅代理服务B,因此在服务A上的特定API中如下所示:
class SomeServiceAPI(APIView):
def get(request):
resp = requests.get('http://service-b.com/api/...')
return Response(resp.json())
虽然这适用于正常状态,但它有一些问题:
问题是,有更好的方法吗?我查看了Django Rest Framework Proxy项目,但我不完全确定它是否真的适合我的用例。
答案 0 :(得分:3)
您可以通过修改Response
:
return Response(resp.json(), status=resp.status_code)
对于第二部分,这是Proxying的本质......(的确,有时你想在代理的中间人中操纵请求和/或响应,但你所做的就是本质)。
注意:
以上两者的一般概念是您创建一个专门用于代理另一个API路径的URL路径:
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似乎更加稳固......
答案 1 :(得分:2)
我查看了John的答案中提到的现有软件包,但它们似乎并不完全适合我的用例,因此我创建了一个简单的包装器来代理请求。对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)