使用Flask代理另一个Web服务

Joe*_*haw 41 python proxy nginx httplib flask

我想将对Flask应用程序发出的请求代理到本机在本地运行的另一个Web服务.我宁愿使用Flask而不是我们的更高级别的nginx实例,这样我们就可以重用我们应用程序内置的现有身份验证系统.我们越能保持这种"单点登录"越好.

是否有现有模块或其他代码来执行此操作?尝试将Flask应用程序连接到像httplib或urllib这样的东西被证明是一种痛苦.

Eva*_*van 61

我花了很多时间研究同样的事情,最终找到了一个使用请求库的解决方案,似乎运行良好.它甚至可以在一个响应中设置多个cookie,这需要进行一些调查才能弄明白.这是烧瓶视图功能:

from flask import request, Response
import requests

def _proxy(*args, **kwargs):
    resp = requests.request(
        method=request.method,
        url=request.url.replace(request.host_url, 'new-domain.com'),
        headers={key: value for (key, value) in request.headers if key != 'Host'},
        data=request.get_data(),
        cookies=request.cookies,
        allow_redirects=False)

    excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
    headers = [(name, value) for (name, value) in resp.raw.headers.items()
               if name.lower() not in excluded_headers]

    response = Response(resp.content, resp.status_code, headers)
    return response
Run Code Online (Sandbox Code Playgroud)

  • 非常好,非常感谢!(这是ngrok需要使用前端和后端的东西.)但是,对于我来说`request.host_url`包括`http://`以及一个尾部斜杠,所以我的替换行是:`request .url.replace(request.host_url,'http://new-domain.com/')` (3认同)
  • @Evan很好的解决方案.但是,它不处理3xx重定向,因为重定向URL可能指向代理主机 (2认同)
  • 有人可以在 MWE 应用程序中添加您如何称呼它吗? (2认同)
  • @Ire我遇到了这个问题,并添加了一个修改的编辑.我所做的只是用`headers = [(name,value)if(name.lower()!='location')else(name,value.replace('http://new-domain.com)替换了标题过滤行. /',request.host_url))对于resp.raw.headers.items()中的(名称,值),如果name.lower()不在excluded_headers]中.这只是修复了Location标头中的URL.(感谢@jbasko指出尾部斜杠的问题) (2认同)
  • 您还可以流式传输响应内容,而不是完全在服务器上读取它。为此,将上面的`resp.content`替换为`resp.iter_content(chunk_size = 10 * 1024)`并在`Response`构造函数中添加`content_type = r.headers ['Content-Type']`参数。 (2认同)

jd.*_*jd. 8

我在基于Werkzeug的应用程序中使用httplib实现了代理(在您的情况下,我需要使用webapp的身份验证和授权).

虽然Flask文档没有说明如何访问HTTP标头,但您可以使用request.headers(参见Werkzeug文档).如果您不需要修改响应,并且代理应用程序使用的标头是可预测的,则代理是明确的.

请注意,如果您不需要修改响应,则应使用werkzeug.wsgi.wrap_file包装httplib的响应流.这允许将开放的OS级文件描述符传递给HTTP服务器以获得最佳性能.


Joe*_*haw 7

我最初的计划是面向公众的URL就像http://www.example.com/admin/myapp代理一样http://myapp.internal.example.com/.沿着这条路走下去会导致疯狂.

大多数webapps,特别是自托管的webapps,都假设它们将在HTTP服务器的根目录下运行,并通过绝对路径引用其他文件.要解决此问题,您必须在整个地方重写URL:位置标头和HTML,JavaScript和CSS文件.

我确实写了一个Flask代理蓝图,它做了这个,虽然它对我真正想要代理的一个webapp工作得很好,但它不可持续.这是正则表达式的一大堆.

最后,我在nginx中设置了一个新的虚拟主机,并使用了自己的代理.由于两者都是主机的根,因此大多数情况下不需要重写URL.(还有什么是必要的,nginx的代理模块处理完毕.)被代理的webapp执行自己的身份验证,现在已经足够了.

  • “我设置了一个新的虚拟主机”的一些插图会很好。 (2认同)