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

Flask中Ajax请求间Session变量无法持久化问题排查

解决Flask后台任务进度无法通过Session实时同步的问题

问题背景

在Flask应用中实现后台任务进度展示:客户端发送请求启动任务,任务循环执行时更新Session中的完成百分比;客户端定期请求获取该Session值展示进度。但实际测试中,获取到的始终是初始值0%,仅偶尔最后一次请求能拿到100%。改用全局变量可正常工作,但无法支持多用户场景。

经测试确认:Session的Cookie收发正常,但Flask需等待更新Session的函数执行完毕后,才会读取到最新值。

现有代码

Flask后端代码

@app.route("/task")
def task():
    session["load_percent"] = 0
    percent = 0
    
    for i in range(10000000):
        # actual task performed here
            
        old_percent = percent
        percent = round(i / 10000000 * 100)
        if old_percent != percent:
            session["load_percent"] = percent
            print("Actual percentage: " + str(session["load_percent"]))
            # this prints the correct value of the session variable

    return "{}"

@app.route("/get_load_percent")
def get_load_percent():
    try:
        print("Retrieved percentage: " + str(session["load_percent"]))
        # this always prints 0
        return json.dumps({"load_percent": session["load_percent"]})
    except (KeyError):
        return "{}"

前端JS代码

function startTask() {
    $.ajax({
        type: "GET",
        url: $('body').data('task'),
        dataType: 'json',
        success: function(response) {
            // respond to task completion here
        }
    });

    let percentageHTML = "";
    let percentageInterval = setInterval(function() {
        $.ajax({
            type: "GET",
            url: $('body').data('getloadpercent'),
            dataType: 'json',
            success: function(response) {
                percentageHTML = response["load_percent"];
                console.log(percentageHTML);
                // always prints 0
            }
        })
    }, 100);
}

问题原因

Flask默认的Session机制是在请求结束时才会将Session数据写入存储或响应Cookie。也就是说,在/task请求的整个处理过程中,循环内对session变量的修改仅保存在当前请求的内存中,不会实时同步到客户端或服务器端的Session存储。只有当/task函数执行完毕返回响应时,才会把最终的Session值发送给客户端,因此在此之前的/get_load_percent请求只能拿到旧的Session数据。

解决方案

方案1:异步任务队列+独立存储(推荐,支持多用户+实时性)

将耗时任务放到异步任务队列(如Celery)中执行,任务进度存入Redis或数据库,用用户的Session ID作为唯一标识,/get_load_percent直接读取对应ID的进度值。

示例代码(依赖Celery+Redis)

  1. 安装依赖:
pip install celery redis
  1. Flask后端改造:
from flask import Flask, session, jsonify
from celery import Celery
import redis

app = Flask(__name__)
app.secret_key = 'your_secret_key_here'

# 配置Celery和Redis
celery = Celery(app.name, broker='redis://localhost:6379/0', backend='redis://localhost:6379/0')
redis_client = redis.Redis(host='localhost', port=6379, db=0)

@celery.task
def run_long_task(session_id):
    percent = 0
    for i in range(10000000):
        # 实际任务逻辑
        old_percent = percent
        percent = round(i / 10000000 * 100)
        if old_percent != percent:
            redis_client.set(f'progress:{session_id}', percent)
    # 任务完成后设置为100%
    redis_client.set(f'progress:{session_id}', 100)

@app.route("/task")
def task():
    session_id = session.sid
    # 初始化进度为0
    redis_client.set(f'progress:{session_id}', 0)
    # 异步启动任务
    run_long_task.delay(session_id)
    return jsonify({})

@app.route("/get_load_percent")
def get_load_percent():
    session_id = session.sid
    percent = redis_client.get(f'progress:{session_id}')
    if percent:
        return jsonify({"load_percent": int(percent)})
    return jsonify({})

方案2:手动强制保存Session(不推荐,仅适合短任务)

如果不想引入异步队列,可以使用服务器端Session存储(如Flask-Session),并在每次更新Session后手动调用session.commit(),强制将修改写入存储。但这种方式会阻塞/task请求,且服务器线程被占用会影响其他请求的响应。

示例代码(依赖Flask-Session+Redis)

  1. 安装依赖:
pip install flask-session redis
  1. Flask后端改造:
from flask import Flask, session, jsonify
from flask_session import Session
import redis

app = Flask(__name__)
app.secret_key = 'your_secret_key_here'

# 配置服务器端Session存储到Redis
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.Redis(host='localhost', port=6379, db=0)
Session(app)

@app.route("/task")
def task():
    session["load_percent"] = 0
    session.commit()  # 初始化后强制保存
    percent = 0
    
    for i in range(10000000):
        # 实际任务逻辑
        old_percent = percent
        percent = round(i / 10000000 * 100)
        if old_percent != percent:
            session["load_percent"] = percent
            session.commit()  # 每次更新后强制保存
            print("Actual percentage: " + str(session["load_percent"]))

    return jsonify({})

内容的提问来源于stack exchange,提问作者Neckroll the 70th

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:31:03