如何在Laravel中将Vue上传的Blob文件正常存储到AWS S3?
如何在Laravel中正确存储前端上传的Blob文件?
我现在用Vue的文件上传插件通过API上传图片和PDF,这个插件支持上传时生成Blob字段,发送给Laravel的请求里能拿到Blob链接(浏览器可以正常访问),但后端用下面的代码存储时,保存的是64字节的损坏文件,不是原文件,请问怎么把Blob正常存到文件系统?
后端当前代码:
if ($request->has('files')) { $files = $request->get('files'); $urls = []; foreach ($files as $file) { $filename = 'files/' . $file['name']; // Upload File to s3 Storage::disk('s3')->put($filename, $file['blob']); Storage::disk('s3')->setVisibility($filename, 'public'); $url = Storage::disk('s3')->url($filename); $urls[] = $url; } return response()->json(['urls' => $urls]); }
问题根源
你碰到的核心问题是:前端传过来的blob字段其实是Blob对象的临时URL(格式类似blob:http://localhost:8080/xxxxxx),而不是文件的原始二进制数据或Base64编码内容。Laravel直接把这个URL字符串写入S3,自然只会生成几十字节的文本文件,而非你要上传的真实文件。
两种解决方案
方案1:后端通过Blob URL拉取真实文件内容(应急方案)
如果受限于插件逻辑,前端只能传Blob URL,你可以在后端通过这个URL请求获取真实的文件数据,再存储到S3:
if ($request->has('files')) { $files = $request->get('files'); $urls = []; foreach ($files as $file) { // 从Blob URL获取文件二进制内容 $fileContent = file_get_contents($file['blob']); if (!$fileContent) { // 处理获取失败的情况(比如跨域、URL过期) continue; } $filename = 'files/' . $file['name']; // 上传至S3 Storage::disk('s3')->put($filename, $fileContent); Storage::disk('s3')->setVisibility($filename, 'public'); $url = Storage::disk('s3')->url($filename); $urls[] = $url; } return response()->json(['urls' => $urls]); }
注意:这种方式依赖后端服务器能访问到前端的Blob URL,如果前后端跨域或Blob URL已过期,会导致获取失败,且效率不如直接传文件。
方案2:前端改用FormData上传(推荐标准方案)
Web开发中文件上传的标准做法是用FormData传递文件,这样Laravel可以直接用原生的文件处理逻辑,完全规避Blob URL的问题:
Vue端示例代码:
// 假设file是你从插件中获取到的文件对象 const formData = new FormData(); // 支持多文件上传,用files[]作为键名 formData.append('files[]', file, file.name); // 发送请求 axios.post('/your-upload-api', formData, { headers: { 'Content-Type': 'multipart/form-data' } });
后端对应调整代码:
if ($request->hasFile('files')) { $urls = []; foreach ($request->file('files') as $file) { if ($file->isValid()) { $filename = 'files/' . $file->getClientOriginalName(); // 直接上传文件至S3 $path = $file->storeAs('', $filename, 's3'); Storage::disk('s3')->setVisibility($path, 'public'); $url = Storage::disk('s3')->url($path); $urls[] = $url; } } return response()->json(['urls' => $urls]); }
这种方式兼容性更强,上传效率更高,也不会出现跨域或URL失效的问题,是长期维护的最优选择。
总结
优先推荐使用FormData的标准上传方案;如果暂时无法修改前端逻辑,再用后端拉取Blob内容的应急方案,但要注意处理URL访问失败的异常情况。
内容的提问来源于stack exchange,提问作者Niraj Pandey
相关产品推荐
相关产品推荐

