# 网关示例:静态前端 + /api 反向代理 + /ai/stream SSE 流式代理 + 限流 + 按 Cookie 灰度 # 运行 test_gateway.py 时会把 {{...}} 占位符替换成临时端口和目录 worker_processes 1; error_log {{PREFIX}}/error.log warn; pid {{PREFIX}}/nginx.pid; events { worker_connections 256; } http { access_log off; # 非 root 运行时,把临时文件目录放到可写位置 client_body_temp_path {{PREFIX}}/client_body; proxy_temp_path {{PREFIX}}/proxy; fastcgi_temp_path {{PREFIX}}/fastcgi; uwsgi_temp_path {{PREFIX}}/uwsgi; scgi_temp_path {{PREFIX}}/scgi; # 每个 IP 每秒 5 个请求,突发最多 5 个 limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s; limit_req_status 429; upstream api_stable { server 127.0.0.1:{{STABLE_PORT}}; keepalive 16; } upstream api_canary { server 127.0.0.1:{{CANARY_PORT}}; keepalive 16; } # Cookie canary=1 的用户走新版本,其余走稳定版本 map $cookie_canary $api_backend { default api_stable; "1" api_canary; } server { listen 127.0.0.1:{{LISTEN_PORT}}; # 前端单页应用:找不到文件时回退到 index.html,交给前端路由 location / { root {{PREFIX}}/html; try_files $uri $uri/ /index.html; } location /api/ { limit_req zone=api_limit burst=5 nodelay; proxy_pass http://$api_backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; 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_connect_timeout 3s; proxy_read_timeout 30s; } # 大模型流式输出(SSE):关闭缓冲,否则 Nginx 攒满缓冲区才发给浏览器 location /ai/stream { proxy_pass http://api_stable; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_buffering off; proxy_cache off; proxy_read_timeout 300s; # 生成时间长,读超时要放宽 add_header X-Accel-Buffering no; } } }