nginx动态匹配(分流)

如果实例是固定的几个,可以直接在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;
    }
}
相关推荐
舒一笑21 小时前
我把前端从 /ais 改到 /kb 后,连续踩了 7 个 Nginx 坑(含 405/413/502/404 终极解法)
运维·nginx·程序员
东北甜妹1 天前
Redis 知识总结
运维·nginx·安全
Cyber4K1 天前
【Nginx专项】基础入门篇-日志格式、日志分类、日志缓存及日志轮转
运维·服务器·nginx·缓存
观无1 天前
html+nginx实现看板
前端·nginx·html
.柒宇.2 天前
nginx入门教程
运维·nginx
如来神掌十八式2 天前
nginx + spring gateway+spring 服务_nginx 转发到 gateway
nginx·spring·gateway
hotlinhao2 天前
Nginx rewrite last 与 redirect 的区别——Vue history 模式短链接踩坑记录
前端·vue.js·nginx
tryCbest3 天前
Nginx常用操作命令-Linux和Windows系统
linux·windows·nginx
難釋懷3 天前
Nginx实现本地缓存查询
nginx·spring·缓存