如果实例是固定的几个,可以直接在nginx.conf中配置upstream进行负载均衡,但是如果这个实例是由用户动态添加的,这种方式就不行了。可以考虑:
1、nginx层Lua实现,存在以下问题:
- 需要安装lua
- 重做nginx容器
2、python后端拦截器
前端请求 --> nginx代理到flask服务 --> python路由服务 --> 代码逻辑拿到实例地址 --> 转发请求到指定实例 --> 返回响应给前端
nifi-api_flask-1.py 与 nifi-api_flask-2.py:
python
from flask import Flask
from markupsafe import escape
app = Flask(__name__)
@app.route('/nifi-api', methods=['GET']) # 没有声明请求方式,默认是get请求
def hello_world():
return "<p>Hello, World!</p>"
@app.route('/nifi-api/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return f'User {escape(username)}'
@app.route('/nifi-api/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return f'Post {post_id}'
@app.route('/nifi-api/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return f'Subpath {escape(subpath)}'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8001)

main_flask.py: dispatch_request不会自动处理post等请求,受到Flask-restful限制(GET/HEAD/OPTIONS),可分别get、post跳转到dispatch_request处理
python
from flask import Flask, Blueprint, request, Response
from flask_restful import Api, Resource
import httpx
import random
# -------------------- 数据库查询函数 --------------------
def get_nifi_url_for_user(user_id: int):
"""
根据 user_id 从数据库中查出对应的 NiFi 实例 URL
"""
map_dict = {
1: "http://192.168.208.131:8001",
2: "http://192.168.208.131:8002",
}
return map_dict[user_id]
# -------------------- NiFi 动态代理类 --------------------
class NifiProxyApi(Resource):
def get(self, path=None):
return self.dispatch_request(path)
def post(self, path=None):
return self.dispatch_request(path)
def put(self, path=None):
return self.dispatch_request(path)
def delete(self, path=None):
return self.dispatch_request(path)
def patch(self, path=None):
return self.dispatch_request(path)
def options(self, path=None):
return self.dispatch_request(path)
def dispatch_request(self, path=None):
"""
统一入口,拦截所有 /nifi-api/<path:path> 请求
根据用户查数据库,然后转发到对应 NiFi 实例
"""
# 1. 获取用户 ID(可改为 JWT 或 session)
user_id = random.choice([1, 2])
print(f"user_id : {user_id}")
if not user_id:
return Response("缺少用户信息", status=401)
# 2. 查数据库获取对应 NiFi 实例地址
nifi_url = get_nifi_url_for_user(user_id)
print(f"nifi_url: {nifi_url}")
if not nifi_url:
return Response("未找到该用户对应的 NiFi 实例", status=404)
# 3. 构建目标 URL
target_url = f"{nifi_url}/nifi-api/{path}" if path else f"{nifi_url}/nifi-api"
method = request.method
body = request.get_data()
# 过滤掉 Host 避免冲突
headers = {k: v for k, v in request.headers if k.lower() != 'host'}
print(f"target_url: {target_url}, method: {method}, body: {body}, params: {request.args}")
# 4. 转发请求到 NiFi
with httpx.Client(verify=False) as client:
resp = client.request(
method=method,
url=target_url,
headers=headers,
content=body,
params=request.args
)
# 5. 过滤掉不适合直接返回给客户端的头部
excluded_headers = ['content-encoding', 'transfer-encoding', 'connection']
response_headers = [(k, v) for k, v in resp.headers.items() if k.lower() not in excluded_headers]
# 6. 将 NiFi 响应返回给前端
return Response(resp.content, resp.status_code, response_headers)
# -------------------- Flask 应用与路由注册 --------------------
app = Flask(__name__)
# Blueprint 路由前缀
bp = Blueprint("console", __name__, url_prefix="/console/api")
api = Api(bp)
# 注册 NiFi 代理接口,同时支持根路径和多级路径 给 <path:path> 提供默认值
api.add_resource(NifiProxyApi, "/nifi-api/","/nifi-api/<path:path>")
# 注册 Blueprint
app.register_blueprint(bp)
# -------------------- 主入口 --------------------
if __name__ == "__main__":
# 监听 8000 端口,可自行修改
app.run(host="0.0.0.0", port=8000, debug=True)
1
python
server {
listen 80;
location /nifi-api {
proxy_pass http://192.168.208.131:8000/console/api/nifi-api;
autoindex off;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
}
location / {
root /usr/share/nginx/html;
index index.html;
}
}
