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

AJAX调用长耗时run.py脚本仅显示部分输出的问题排查

问题根源

普通AJAX是一次性请求-响应模型:前端发请求后,服务器会默认把脚本的所有输出先缓冲起来,直到脚本完全执行完毕,才一次性把响应返回给前端。你的run.py要跑2分钟,自然拿不到中间的输出内容。

解决方案1:用Server-Sent Events(SSE)实时推送

这是最适合这种单向实时输出场景的方案,实现起来简单,不需要额外依赖。

前端JS代码

把你的AJAX换成SSE连接,实时接收服务器推送的输出:

$(document).ready(function(){
    $('#sub').click(function(){
        alert("connecting to host");
        // 创建SSE连接,指向你的Python脚本
        const eventSource = new EventSource('/cgi-bin/run.py');
        
        // 每次收到服务器消息,追加到页面的输出容器(比如<div id="output"></div>)
        eventSource.onmessage = function(event) {
            $('#output').append(event.data + '<br>');
        };
        
        // 脚本执行完后,服务器会关闭连接,这里处理结束逻辑
        eventSource.onclose = function() {
            alert("脚本执行完成");
            eventSource.close();
        };
        
        // 处理连接错误
        eventSource.onerror = function(error) {
            console.error('连接出错:', error);
            eventSource.close();
        };
    });
});

修改run.py脚本

要输出SSE格式的内容,同时强制刷新输出缓冲区,避免服务器缓冲:

#!/usr/bin/env python3
import sys
import time

# 设置SSE要求的响应头,告诉浏览器这是流式事件
print("Content-Type: text/event-stream")
print("Cache-Control: no-cache")
print("Connection: keep-alive")
print()  # 必须用空行分隔响应头和内容

# 模拟你的长时间任务,这里每12秒输出一次,总时长2分钟
for step in range(1, 11):
    # SSE的消息格式是:data: 内容\n\n
    print(f"data: 当前执行第 {step} 步...")
    print()
    sys.stdout.flush()  # 关键:强制把输出推送给前端,不要缓冲
    time.sleep(12)

# 发送执行完成的消息,然后关闭连接
print("data: 脚本执行完成!")
print()
sys.stdout.flush()
解决方案2:轮询获取输出(兼容旧浏览器)

如果你的场景需要兼容不支持SSE的旧浏览器,可以用轮询方案:前端定期请求服务器,获取脚本的最新输出。

前端JS代码

$(document).ready(function(){
    let lastOutputLength = 0;
    let pollTimer;
    
    $('#sub').click(function(){
        alert("connecting to host");
        // 先发送请求启动脚本
        $.ajax({
            type:'POST',
            url:'/cgi-bin/start_run.py',
            success:function(){
                // 每5秒轮询一次,获取最新输出
                pollTimer = setInterval(function(){
                    $.get('/cgi-bin/get_output.py', function(currentOutput){
                        // 只显示新增的内容,避免重复输出
                        const newContent = currentOutput.slice(lastOutputLength);
                        if(newContent){
                            $('#output').append(newContent + '<br>');
                            lastOutputLength = currentOutput.length;
                        }
                        // 判断脚本是否执行完成(比如输出包含特定关键词)
                        if(currentOutput.includes("脚本执行完成")){
                            clearInterval(pollTimer);
                            alert("脚本执行结束");
                        }
                    });
                }, 5000);
            }
        });
    });
});

配套Python脚本

  1. start_run.py:负责后台启动run.py,并把输出写到临时文件
#!/usr/bin/env python3
import subprocess
import os

# 临时文件路径,用来保存脚本输出
OUTPUT_FILE = '/tmp/run_script_output.txt'

# 启动run.py,后台运行,把标准输出和错误输出都写到临时文件
subprocess.Popen(
    ['python3', '/cgi-bin/run.py'],
    stdout=open(OUTPUT_FILE, 'w'),
    stderr=subprocess.STDOUT
)

# 返回响应给前端
print("Content-Type: text/html")
print()
print("脚本已启动,正在执行...")
  1. run.py:你的原有脚本,正常输出内容即可
#!/usr/bin/env python3
import time

for step in range(1, 11):
    print(f"执行第 {step} 步,处理中...")
    time.sleep(12)

print("脚本执行完成")
  1. get_output.py:读取临时文件的内容,返回给前端
#!/usr/bin/env python3
import os

OUTPUT_FILE = '/tmp/run_script_output.txt'

# 设置响应头
print("Content-Type: text/plain")
print()

# 读取并返回输出内容
if os.path.exists(OUTPUT_FILE):
    with open(OUTPUT_FILE, 'r') as f:
        print(f.read(), end='')
关键注意事项
  • 服务器长连接配置:如果用Apache,需要调整ScriptTimeout(默认300秒,足够覆盖你的2分钟任务);如果用Nginx,要调整proxy_read_timeout等参数,避免服务器提前断开长连接。
  • 强制刷新输出:Python脚本里一定要加sys.stdout.flush(),否则输出会被系统缓冲,直到脚本结束才发送。
  • CGI运行限制:有些服务器会限制CGI脚本的运行时间,需要检查并调整对应配置。

内容的提问来源于stack exchange,提问作者Rithesh Bhat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:47:46