我希望将发送到我的Flask应用程序的请求代理到另一台在本地运行的Web服务。 我宁愿使用Flask来实现这个功能,而不是我们的高级nginx实例,这样我们就可以重用我们应用程序中内置的现有身份验证系统。 这样我们就能更好地保持“单点登录”的效果。
是否有现成的模块或其他代码可用于此? 尝试通过类似httplib或urllib的方式连接Flask应用程序已经变得非常棘手。
我希望将发送到我的Flask应用程序的请求代理到另一台在本地运行的Web服务。 我宁愿使用Flask来实现这个功能,而不是我们的高级nginx实例,这样我们就可以重用我们应用程序中内置的现有身份验证系统。 这样我们就能更好地保持“单点登录”的效果。
是否有现成的模块或其他代码可用于此? 尝试通过类似httplib或urllib的方式连接Flask应用程序已经变得非常棘手。
from dotenv import load_dotenv # pip package python-dotenv
import os
#
from flask import request, Response
import requests # pip package requests
load_dotenv()
API_HOST = os.environ.get('API_HOST'); assert API_HOST, 'Envvar API_HOST is required'
@api.route('/', defaults={'path': ''}, methods=["GET", "POST"]) # ref. https://medium.com/@zwork101/making-a-flask-proxy-server-online-in-10-lines-of-code-44b8721bca6
@api.route('/<path>', methods=["GET", "POST"]) # NOTE: better to specify which methods to be accepted. Otherwise, only GET will be accepted. Ref: https://flask.palletsprojects.com/en/3.0.x/quickstart/#http-methods
def redirect_to_API_HOST(path): #NOTE var :path will be unused as all path we need will be read from :request ie from flask import request
res = requests.request( # ref. https://dev59.com/rWw15IYBdhLWcg3wYKmo#36601467
method = request.method,
url = request.url.replace(request.host_url, f'{API_HOST}/'),
headers = {k:v for k,v in request.headers if k.lower() != 'host'}, # exclude 'host' header
data = request.get_data(),
cookies = request.cookies,
allow_redirects = False,
)
#region exlcude some keys in :res response
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] #NOTE we here exclude all "hop-by-hop headers" defined by RFC 2616 section 13.5.1 ref. https://www.rfc-editor.org/rfc/rfc2616#section-13.5.1
headers = [
(k,v) for k,v in res.raw.headers.items()
if k.lower() not in excluded_headers
]
#endregion exlcude some keys in :res response
response = Response(res.content, res.status_code, headers)
return response
request.host_url
包括http://
和一个尾随斜杠,因此对于我来说,替换行如下:request.url.replace(request.host_url, 'http://new-domain.com/')
。 - jbaskoheaders = [(name, value) if (name.lower() != 'location') else (name, value.replace('http://new-domain.com/', request.host_url)) for (name, value) in resp.raw.headers.items() if name.lower() not in excluded_headers]
替换了头部过滤器行。这只是修复了 Location 头中的 URL。(感谢 @jbasko 指出了尾随斜杠的问题) - Eric Reedresp.content
替换为 resp.iter_content(chunk_size=10*1024)
,并在 Response
构造函数中添加 content_type=r.headers['Content-Type']
参数。 - Tim我在一个基于Werkzeug的应用程序中使用httplib实现了一个代理(就像你的情况一样,我需要使用Web应用程序的身份验证和授权)。
尽管Flask文档没有说明如何访问HTTP头,但是你可以使用request.headers
(参见Werkzeug文档)。如果你不需要修改响应,并且被代理应用程序使用的标头是可预测的,那么代理就很容易。
请注意,如果您不需要修改响应,则应使用werkzeug.wsgi.wrap_file
来包装httplib的响应流。这允许传递打开的操作系统级文件描述符以获得最佳性能。
http://www.example.com/admin/myapp
,代理到http://myapp.internal.example.com/
。但这条路会走向疯狂。