FilePond结合Laravel从外部URL获取PDF文件异常问题排查
FilePond处理外部PDF链接时的文件损坏问题
问题背景
使用FilePond的fetch功能加载外部PDF链接时出现异常:
- FilePond显示的文件大小远大于实际的2.3M
- 使用PdfParser验证该PDF时出错,但本地上传同一文件完全正常
- 怀疑是fetch过程中的Blob转换导致文件损坏
前端fetch代码
fetch: (source, load, error, progress, abort, headers) => { //progress(true, 0, 1024); axios({ // headers: {'Access-Control-Expose-Headers': 'Content-Disposition'}, method: 'get', url: 'fetch?url='+source, onUploadProgress: (e) => { // updating progress indicator progress(true, e.loaded, e.total); } }).then(response => { // passing the file id to Filepond if (response.status === 200) { let blob = new Blob([response.data],{ type: "application/pdf" }) load(blob) } }).catch((thrown) => { if (axios.isCancel(thrown)) { console.log('Request cancelled', thrown.message); } else { // handle error error(error) console.log(thrown) } }) },
Laravel后端端点代码
public function fetch(Request $request) { $url = $request->url; $headers = [ 'Content-Type' => 'application/pdf', ]; return response()->stream(function () use ($url) { $file = fopen($url, 'rb'); fpassthru($file); fclose($file); }, 200, $headers); }
load函数代码
load: (source, load, error, progress, abort, headers) => { // Should get a file object from the URL here // ... console.log(source) // Should call the progress method to update the progress to 100% before calling load // (computable, loadedSize, totalSize) //progress(true, 0, 1024); // Should call the load method with a file object when done load(source); // Should expose an abort method so the request can be cancelled return { abort: () => { // Let FilePond know the request has been cancelled abort(); } }; },
排查与修复方案
1. 前端axios请求未正确处理二进制数据
axios默认会把响应解析为JSON格式,这会导致二进制PDF数据被错误转换为字符串,后续再转Blob就会损坏文件。
修改前端fetch代码:给axios添加responseType: 'blob'配置,直接获取Blob对象:
fetch: (source, load, error, progress, abort, headers) => { axios({ method: 'get', url: 'fetch?url='+source, responseType: 'blob', // 关键配置:指定响应类型为blob onUploadProgress: (e) => { progress(true, e.loaded, e.total); } }).then(response => { if (response.status === 200) { // 直接使用响应返回的Blob,无需手动创建 load(response.data) } }).catch((thrown) => { if (axios.isCancel(thrown)) { console.log('Request cancelled', thrown.message); } else { error(thrown.message) // 传递具体错误信息 console.log(thrown) } }) },
2. 后端响应优化
当前后端使用stream返回文件流,可能存在未正确设置文件大小的问题,导致前端无法获取准确的文件总大小。可以修改后端代码,先获取文件内容和大小,再返回:
public function fetch(Request $request) { $url = $request->url; // 获取文件内容和大小 $fileContent = file_get_contents($url); $fileSize = strlen($fileContent); $headers = [ 'Content-Type' => 'application/pdf', 'Content-Length' => $fileSize, // 添加文件大小头 ]; return response()->make($fileContent, 200, $headers); }
注意:如果外部URL是远程地址,
file_get_contents需要确保服务器允许访问该地址,可在php.ini中设置allow_url_fopen = On。
3. 完善load函数状态更新
当前load函数逻辑正确,但可以补充进度更新,确保FilePond能正确显示加载状态:
load: (source, load, error, progress, abort, headers) => { console.log(source) // 更新进度为100% progress(true, source.size, source.size); // 加载Blob对象 load(source); return { abort: () => { abort(); } }; },
验证修复
修改后重新测试:
- 检查FilePond显示的文件大小是否与实际一致
- 使用PdfParser验证加载后的PDF是否正常
- 确认文件能正常预览或打开
内容的提问来源于stack exchange,提问作者Mihai
相关产品推荐
相关产品推荐

