Laravel中用DOMPdf渲染Chart图表至PDF失败求助
解决Laravel中Chart.js图表无法渲染到DOMPDF生成的PDF问题
核心问题分析
你的代码存在三个关键问题:
- 前端POST请求未携带CSRF令牌,被Laravel拦截
- 图片存储路径与PDF视图中引用路径不匹配,DOMPDF无法找到图片
- 后端重复执行数据库查询(前端已传图片数据,无需再查)
修复步骤与代码修改
1. 修复前端CSRF令牌问题(chart.blade.php)
Laravel默认会验证POST请求的CSRF令牌,需在请求头中加入:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <!-- 添加CSRF令牌meta标签 --> <meta name="csrf-token" content="{{ csrf_token() }}"> <title>Document</title> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8"> <canvas id="myChart" height="100px"></canvas> </div> <button id="convertButton">pdf</button> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js" charset="utf-8"></script> <script type="text/javascript"> var labels = {{ Js::from($labels) }}; var users = {{ Js::from($data) }}; const data = { labels: labels, datasets: [{ label: 'My First dataset', backgroundColor: 'rgb(255, 99, 132)', borderColor: 'rgb(255, 99, 132)', data: users, }] }; const config = { type: 'line', data: data, options: {} }; const myChart = new Chart( document.getElementById('myChart'), config ); </script> <script> const canvas = document.getElementById('myChart'); const convertButton = document.getElementById('convertButton'); convertButton.addEventListener('click', () => { const canvasData = canvas.toDataURL(); // 获取CSRF令牌 const csrfToken = document.querySelector('meta[name="csrf-token"]').content; fetch('/pdf', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-CSRF-TOKEN': csrfToken // 加入CSRF令牌头 }, body: `imageData=${encodeURIComponent(canvasData)}` }) .then(response => response.blob()) // 改为获取blob,适配PDF流返回 .then(blob => { // 直接在浏览器中打开PDF const url = window.URL.createObjectURL(blob); window.open(url); }); }); </script> </body> </html>
2. 修复后端存储与路径问题(/pdf路由处理函数)
去掉多余的数据库查询,修正图片存储路径与访问URL:
public function generatePDF(Request $request) { $imageData = $request->input('imageData'); if (!$imageData) { return response()->json(['message' => '图片数据缺失'], 400); } // 移除数据URL前缀 $imageData = str_replace('data:image/png;base64,', '', $imageData); $decodedImageData = base64_decode($imageData); // 生成唯一文件名(避免覆盖) $filename = 'chart_' . uniqid() . '.png'; // 存储到public磁盘(需先执行php artisan storage:link创建符号链接) Storage::disk('public')->put($filename, $decodedImageData); // 获取可访问的图片URL $imageUrl = Storage::url($filename); // 加载PDF视图 $pdf = PDF::loadView('pdf', compact('imageUrl')); return $pdf->stream('chart.pdf'); }
3. 修复PDF视图图片引用(pdf.blade.php)
使用正确的存储URL而非本地文件路径:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8"> <img src="{{ $imageUrl }}" alt="charts" style="width: 100%;"> </div> </div> </div> </body> </html>
关键注意事项
- 执行
php artisan storage:link命令,将storage/app/public目录链接到public/storage,确保DOMPDF能访问到存储的图片。 - 若DOMPDF仍无法加载图片,可尝试使用绝对URL(如
url($imageUrl)),或在DOMPDF配置中开启isRemoteEnabled选项。 - 前端返回处理改为blob,直接打开PDF,避免之前的JSON解析错误(因为后端返回的是PDF流,不是JSON)。
内容的提问来源于stack exchange,提问作者Nevil Aghera
相关产品推荐
相关产品推荐

