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

Heroku部署Flask上传MP4文件无报错但未保存问题排查

你找不到文件的根本原因
  • heroku run bash启动的是和运行中web服务完全隔离的一次性独立dyno,Heroku每个dyno都有独立的临时文件系统,互相不共享,你在这个一次性bash环境里执行ls,永远看不到web dyno里写入的文件,这是平台架构设计,不是文件保存失败。
  • 你的代码本身存在逻辑bug:调用uploaded_file.read()读取内容后,文件流指针会直接移动到内容末尾,后续再执行uploaded_file.save()时,读不到任何有效流内容,无法写出完整文件,本地环境能运行属于偶发兼容,不是逻辑正确。
可直接落地的解决方案

你不需要持久化存储,仅临时处理视频的需求完全可以在Heroku上实现,两种方案选其一即可:

方案1:修正落盘逻辑,在请求生命周期内完成处理

Heroku的/tmp目录是所有dyno默认可写的临时目录,适合短时间存放文件,注意所有读写、处理、删除操作必须在同一个接口请求的生命周期内完成,不要跨请求留文件:

import os
import cv2
from flask import Flask, request
from flask_cors import CORS

app = Flask(__name__)
# 统一用/tmp目录避免权限问题
app.config['UPLOAD_PATH'] = '/tmp'
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

@app.route('/api/uploadFile', methods=['POST'])
def uploadFile():
    uploaded_file = request.files['uploadedfile']
    if uploaded_file.filename == '':
        return {"status": "fail", "msg": "no file uploaded"}
    
    save_path = os.path.join(app.config['UPLOAD_PATH'], uploaded_file.filename)
    # 先保存文件,不要提前read()移动流指针
    uploaded_file.save(save_path)

    # 同请求内直接读取处理
    cap = cv2.VideoCapture(save_path)
    frame_list = []
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        frame_list.append(frame)
    cap.release()

    # 处理完主动删除文件释放空间
    os.remove(save_path)

    # 后续写你的帧处理逻辑,返回结果即可
    return {"status": "success", "frame_count": len(frame_list)}

方案2:内存直接处理,完全不写物理磁盘

更高效的方式是不落地写文件,直接把读取到的字节流转为OpenCV可识别的临时文件对象,减少磁盘IO,也不用手动清理文件:

import cv2
import tempfile
from flask import Flask, request
from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

@app.route('/api/uploadFile', methods=['POST'])
def uploadFile():
    uploaded_file = request.files['uploadedfile']
    if uploaded_file.filename == '':
        return {"status": "fail", "msg": "no file uploaded"}
    
    content = uploaded_file.read()
    # 生成自动销毁的内存临时文件
    with tempfile.NamedTemporaryFile(delete=True, suffix='.mp4') as tmp_file:
        tmp_file.write(content)
        tmp_file.flush()
        cap = cv2.VideoCapture(tmp_file.name)
        frame_list = []
        while True:
            ret, frame = cap.read()
            if not ret:
                break
            frame_list.append(frame)
        cap.release()
    # 退出with块后临时文件自动删除,无需手动处理

    return {"status": "success", "frame_count": len(frame_list)}
调试注意事项

不要通过heroku run bash进入独立dyno排查文件是否存在,你可以在代码里保存文件后加print(os.path.getsize(save_path))这类调试语句,日志可以通过heroku logs --tail命令直接查看,结果准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:12:28