Laravel PHP服务调用Python服务传递文件避免死锁方案咨询
解决PHP调用Python服务时的文件传递死锁问题
你遇到的死锁问题核心逻辑很清晰:PHP发起POST请求到Python服务后,会一直持有连接等待响应;而Python服务此时尝试通过HTTP请求从PHP服务器下载文件,如果你的PHP服务器是单进程模式(比如用php -S启动的内置开发服务器),它会被当前的请求完全占用,无法处理Python的下载请求,最终导致两边互相等待,形成死锁。
下面给你几个可行的解决方案,按推荐程度排序:
方案1:直接在POST请求中上传文件内容
最直接的解决方式是跳过“传URL再下载”的冗余环节,PHP在发起POST请求时直接把文件内容作为请求的一部分发送给Python,这样Python不需要再反向请求PHP服务器,从根源上避免死锁。
修改后的PHP代码
我们改用multipart/form-data格式来上传文件(用curl实现更稳定):
<?php // 替换为你的docx文件路径 $filePath = storage_path('app/documents/test.docx'); $fileName = basename($filePath); // 初始化curl请求 $ch = curl_init('http://localhost:5000/api/extraction'); curl_setopt($ch, CURLOPT_POST, true); // 构建上传表单 $postFields = [ 'file' => new CURLFile( $filePath, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', $fileName ) ]; curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); // 设置超时和结果返回方式 curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 执行请求并处理结果 $result = curl_exec($ch); curl_close($ch); var_dump($result); ?>
修改后的Python代码
Flask直接接收上传的文件即可:
from flask import Flask, request from werkzeug.utils import secure_filename import os app = Flask(__name__) app.config['UPLOAD_FILE_FOLDER'] = '/path/to/your/python/upload/folder' @app.route('/api/extraction', methods=['POST']) def extraction(): if 'file' not in request.files: return 'No file uploaded', 400 file = request.files['file'] if file.filename == '': return 'No selected file', 400 if file: filename = secure_filename(file.filename) path = os.path.join(app.config['UPLOAD_FILE_FOLDER'], filename) file.save(path) # 这里添加你的Word文档数据提取逻辑 return 'File processed successfully', 200 if __name__ == '__main__': app.run()
方案2:确保PHP服务器支持多并发请求
如果你坚持要使用“传递文件URL”的方式,那必须确保你的PHP服务器能够同时处理多个请求,避免因为当前的POST请求占用进程,无法响应Python的下载请求。
- 如果你之前用的是
php -S启动的内置开发服务器,它是单进程的,这是死锁的核心诱因。可以换成Nginx+PHP-FPM的生产环境配置;如果是Laravel项目,也可以用多进程启动开发服务器:php artisan serve --workers=4。 - Python这边的代码可以保持你原来的写法,只要PHP服务器能同时处理两个请求(PHP发往Python的POST、Python发往PHP的下载请求),死锁问题就会消失。
方案3:使用共享存储传递文件
另一种思路是把文件放到PHP和Python都能访问的共享存储中,彻底绕开HTTP反向请求:
- 本地共享目录(如果两个服务部署在同一台机器上)
- Redis(存储文件二进制内容)
- 对象存储(比如MinIO、本地自建存储服务)
举个本地共享目录的简单例子:
- PHP把docx文件保存到双方都有权限访问的目录,比如
/opt/shared_docs/ - PHP在POST请求中传递文件的共享路径(比如
/opt/shared_docs/test.docx) - Python直接从这个路径读取文件,不需要通过HTTP下载
这种方式也能完美避免死锁,适合两个服务部署在同一机器或同一局域网的场景。
内容的提问来源于stack exchange,提问作者Snakies
相关产品推荐
相关产品推荐

