You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:00:12