Django reverse()在API网关/代理下的URL生成问题求助
解决Django REST API在Kong网关后reverse生成正确URL的问题
核心思路
Kong会通过X_FORWARDED_HOST和X_FORWARDED_PATH传递网关的域名与basepath,但Django默认仅处理X_FORWARDED_HOST。我们需要通过自定义中间件修改请求的路径前缀,让reverse()和HyperlinkedModelSerializer生成基于网关basepath的URL。
步骤1:配置Django信任代理头
在settings.py中添加以下配置,确保Django正确识别Kong转发的请求头:
ALLOWED_HOSTS = ['apigatewayurl.com', 'mydomain.com'] # 替换为实际的网关和上游域名 USE_X_FORWARDED_HOST = True USE_X_FORWARDED_PORT = True # 若网关使用HTTPS,添加以下配置 SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
步骤2:编写自定义中间件处理X_FORWARDED_PATH
创建中间件文件myapp/middleware.py(替换为你的应用名),实现请求路径的调整逻辑:
class XForwardedPathMiddleware: def __init__(self, get_response): self.get_response = get_response self.original_upstream_prefix = '/py/api/v1' # 你的上游路径前缀 def __call__(self, request): # 获取Kong传递的网关basepath forwarded_path = request.META.get('HTTP_X_FORWARDED_PATH', '') if forwarded_path: # 清理路径末尾斜杠,避免重复拼接 forwarded_path = forwarded_path.rstrip('/') # 将请求的script_name设置为网关basepath,reverse会以此为前缀 request.script_name = forwarded_path # 移除请求路径中原有的上游前缀,确保Django路由匹配正常 if request.path.startswith(self.original_upstream_prefix): request.path = request.path[len(self.original_upstream_prefix):] or '/' response = self.get_response(request) return response
步骤3:注册中间件
在settings.py的MIDDLEWARE列表中添加自定义中间件,注意要放在CommonMiddleware之前:
MIDDLEWARE = [ # ...其他系统中间件 'myapp.middleware.XForwardedPathMiddleware', 'django.middleware.common.CommonMiddleware', # ...其他中间件 ]
步骤4:调整路由去除末尾斜杠(可选)
若需要生成不带末尾斜杠的URL(如/gateway-basepath/users),初始化路由时关闭trailing_slash:
# urls.py router = routers.DefaultRouter(trailing_slash=False) router.register(r'users', views.UserViewSet)
验证效果
完成配置后:
- APIRootView中
reverse('user-list', request=request)会生成apigatewayurl.com/gateway-basepath/users - UserSerializer的
url字段也会生成相同格式的正确URL
内容的提问来源于stack exchange,提问作者Ewro
相关产品推荐
相关产品推荐

