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
相关产品推荐
相关产品推荐

