Flask全局变量在Nginx下失效,Gunicorn运行正常问题排查
问题原因与解决方案
问题核心原因
你遇到的问题本质是Gunicorn多进程模式下全局变量的进程隔离特性:
- 直接用
gunicorn --bind 0.0.0.0:5000 wsgi:app启动时,若机器为单核,Gunicorn默认仅启动1个worker进程,所有请求复用同一个进程的全局变量secret_number,因此功能正常。 - 通过Nginx转发时,Gunicorn通常会启动多个worker进程(默认数量等于CPU核心数),每个worker在启动时都会重新加载Flask应用模块,独立执行
secret_number = gen_secret_number()生成专属随机数。Nginx会将请求分发到不同worker,导致每次请求对应的随机数不一致,自然无法匹配用户输入。
全局变量是进程私有资源,多worker场景下绝对不能用来存储需要跨请求保持的用户状态。
解决方案:改用Flask Session存储状态
Flask的session基于用户会话绑定,会通过加密Cookie或分布式存储保持跨进程/服务器的一致性,完全适配多worker部署场景。
修改后的Flask视图代码
from flask import Flask, request, render_template, redirect, url_for, session import random app = Flask(__name__) # 必须配置加密密钥,生产环境请使用随机生成的密钥(如secrets.token_hex(16)) app.secret_key = 'your-secure-random-key-here' def gen_secret_number(): return random.randint(1, 100) @app.route('/', methods=['GET', 'POST']) def guess_number(): # 初始化会话中的秘密数字(首次访问或重置后生成) if 'secret_number' not in session: session['secret_number'] = gen_secret_number() secret_number = session['secret_number'] message = None if request.method == 'POST': entered_value = int(request.form['number']) if entered_value == secret_number: message = "Well done" # 猜对后清空会话中的数字,下次访问自动生成新数 session.pop('secret_number', None) elif entered_value < secret_number: message = "Too small" else: message = "Too big" return render_template('index.html', message=message) @app.route('/reset', methods=['POST']) def reset(): # 清空会话中的秘密数字 session.pop('secret_number', None) return redirect(url_for('guess_number')) if __name__ == '__main__': app.run(debug=True)
修改后的表单代码
(移除了前端暴露秘密数字的逻辑,避免泄露答案)
<form method="post" action="{{ url_for('guess_number') }}"> <label for="number">Enter your number :</label> <input type="number" id="number" name="number" required> <button type="submit">Guess</button> </form> <form method="post" action="{{ url_for('reset') }}"> <button type="submit">Restart</button> </form> {% if message %} <h4>{{ message }}</h4> {% endif %}
补充注意事项
- 生产环境中
SECRET_KEY必须使用随机生成的高复杂度字符串,绝对不能硬编码固定值。 - 如果需要多服务器集群部署,建议改用Redis等分布式session存储,避免Cookie存储的容量和安全性限制。
- 绝对不要将敏感业务数据(如本题的秘密数字)暴露到前端模板中,这会直接破坏业务逻辑的安全性。
内容的提问来源于stack exchange,提问作者mannaia
相关产品推荐
相关产品推荐

