如何仅用 Django 实现反向代理?

2022-04-07 20:13:56 浏览数 (1)

你好,我是 somenzz,可以叫我征哥。

提到反向代理,你会说用 nginx。没错,nginx 是理想的反向代理工具。

但现在条件苛刻,服务器没有 nginx,也没有 root 权限,意味着你无法编译安装 nginx,且只有一个端口 80 开放访问。怎么让这个 80 端口的某一请求转发到其他端口的 http 服务上?

换句话说,不用 nginx,如何让 http://localhost:80/new_req 的请求转发到 http://localhost:9999 的服务上,就像直接访问 http://localhost:9999 一样?

那么,这就需要我们自己实现反向代理的功能。

本文分享如何仅用 Django 实现反向代理。

1、安装轮子

代码语言:javascript复制
pip install django-revproxy

这个轮子有对应的 whl 文件,非常容易安装成功,且不依赖其他轮子,如果是内网环境,pypi.org 上下载 whl 文件,复制进去 pip 安装一下就可以了。

2、配置

在 Django 的配置文件 settings.py 中的 INSTALLED_APPS 中,添加 'revproxy'。

代码语言:javascript复制
#Add 'revproxy' to INSTALLED_APPS.
INSTALLED_APPS = (
    # ...
    'django.contrib.auth',
    'revproxy',
    # ...
)

然后编写一个视图类,比如 myproxy/views.py:

代码语言:javascript复制
from revproxy.views import ProxyView

class TestProxyView(ProxyView):
    upstream = "http://localhost:9999" ##http://example.com

然后修改 Django 的 urls.py 文件,添加这样一条路由:

代码语言:javascript复制
from myproxy.views import TestProxyView
from django.conf.urls import url

urls = [
   # ...
   url(r'^new_req/(?P<path>.*)$', TestProxyView.as_view()),
   # ...
]

或者,你不想新建一个 views.py 文件,可以直接在 url.py 中这样写:

代码语言:javascript复制
from django.urls import re_path

from revproxy.views import ProxyView

urlpatterns = [
    re_path(r'(?P<path>.*)', ProxyView.as_view(upstream='http://example.com/')),
]

最后,将 Django 服务部署在 80 端口上,然后访问:

http://localhost/new_req

就相当于访问

http://localhost:9999

3、它是如何工作的

这个图就是 django-revproxy 所做的事情:

1、Django 接收来自客户端的请求,并使用 revproxy.proxy.ProxyView 对其进行处理。

2、Revproxy 将克隆客户端请求。

3、如果用户在 Django 中通过身份验证,并且 add_remote_user 属性设置为 True,则 HTTP 标头 REMOTE_USER 将设置为request.user.username。

代码语言:javascript复制
class CustomProxyView(ProxyView):
    upstream = 'http://www.example.com'
    add_remote_user = True
    

4、如果 add_x_forwarded 属性设置为 True,则 HTTP 标头 X-Forwarded-For 和 X-Forwarded-Proto 将分别设置为请求者的 IP 地址和协议(http 或 https)。

5、克隆的请求被发送到上游服务器,也就是 upstream。

6、在收到来自上游的响应后,视图将对其进行处理以确保正确设置所有 headers。一些 headers 像 Location 这样的被视为特殊情况。

7、从上游服务器接收到的响应被转换为 django.http.HttpResponse。对于二进制文件,使用 StreamingHttpResponse 来减少内存使用。

8、如果用户设置了一组 diazo 规则和一个主题模板,则会在响应正文上应用 diazo/XSLT 转换。

views.py :

代码语言:javascript复制
from django.urls import re_path

from revproxy.views import DiazoProxyView

proxy_view = DiazoProxyView.as_view(
    upstream='http://example.com/',
    html5=True,
    diazo_theme_template='base.html',
)

urlpatterns = [
    re_path(r'(?P<path>.*)', proxy_view),
]
    

base.html :

代码语言:javascript复制
<html>
    <head>...</head>
    <body>
        ...
        <div id="content"></div>
        ...Fix all links in the docs (and README file etc) from old to new repo

9、最后,响应将返回给用户。

4、轮子的源代码

来这里一探究竟:django-revproxy[1]

最后的话

分享文件,我比较常用的方式是在某一目录下执行一条 Python 命令: python -m http.server ,可以让该目录下的文件或文件夹通过 http 的方式共享给他人下载使用,使用 django-revproxy 这个轮子,可以让这个功能集成在 Django 的某一个路由中,在开发者服务器部署,大家用起来是着实方便。这也是为什么我找到了这个轮子。

本文分享了如何仅用 Django 就实现反向代理功能,如果觉得有用的话,还请点赞,在看,评论支持。感谢老铁。

参考资料

[1]

django-revproxy: https://github.com/jazzband/django-revproxy

0 人点赞