You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Livewire集成FPDI导出PDF报错解决方案咨询

问题原因分析

出现「SyntaxError: Unexpected token '%', "%PDF-1.5"」错误的核心原因是:Livewire的wire:click触发的是AJAX请求,而FPDF的Output('I', ...)会直接输出PDF二进制内容。AJAX会默认尝试将响应内容解析为JSON格式,而PDF开头的%PDF-1.5不符合JSON语法,因此抛出解析错误。

解决方案

要解决这个问题,需要避开AJAX处理文件下载的场景,改用普通HTTP请求(表单提交/路由跳转)结合Laravel控制器来处理PDF导出:

1. 修改Livewire组件的导出按钮

将原来的wire:click按钮替换为表单提交,直接请求专门的导出路由:

<form action="{{ route('direct-payment.export') }}" method="POST">
    @csrf
    <!-- 传递导出所需的关键参数,比如付款记录ID -->
    <input type="hidden" name="direct_payment_id" value="{{ $data['direct_payment']->id }}">
    <button type="submit" class="btn btn-warning text-white me-2">
        <i class="bi bi-download"></i>
        <span class='btn-text'>Export</span>
    </button>
</form>

2. 添加导出路由

在routes/web.php中新增POST路由,指向控制器的导出方法:

use App\Http\Controllers\DirectPaymentController;

Route::post('/direct-payment/export', [DirectPaymentController::class, 'export'])
    ->name('direct-payment.export');

3. 迁移导出逻辑到控制器

将原来Livewire组件中的静态export方法迁移到控制器,并调整PDF输出方式,用Laravel的响应系统返回正确的PDF内容:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use setasign\Fpdi\Fpdi;
use App\Models\DirectPayment;
use App\Http\Controllers\Bir2307DateController;

class DirectPaymentController extends Controller
{
    public function export(Request $request)
    {
        // 获取导出所需数据
        $directPayment = DirectPayment::findOrFail($request->direct_payment_id);
        // 根据你的业务逻辑获取公司信息,示例为从认证用户关联获取
        $company = auth()->user()->company;
        $data = [
            'direct_payment' => $directPayment,
            'company' => $company
        ];

        // 原有的PDF生成逻辑
        $period_month = date('n', strtotime($data['direct_payment']->date));
        $get_year = date('Y', strtotime($data['direct_payment']->date));
        $previos_quarter_month = Bir2307DateController::CheckBirPreviousMonth($period_month);
        $period_from = date($previos_quarter_month.'01'.$get_year);
        $last_quarter_month = app(Bir2307DateController::class)->CheckBirLastQuartMonth($period_month);
        $last_day = cal_days_in_month(CAL_GREGORIAN, $last_quarter_month, $get_year);
        $period_to = date($last_quarter_month.$last_day.$get_year);
        $period_from_split = str_split($period_from);
        $period_to_split = str_split($period_to);
        $vendor_tin = str_split($data['direct_payment']->vendorCustomer->tin);
        $vendor_zip_code = str_split($data['direct_payment']->vendorCustomer->address_zip_code);
        $vendor_address = $data['direct_payment']->vendorCustomer->address_street.", ".$data['direct_payment']->vendorCustomer->address_city.", ".$data['direct_payment']->vendorCustomer->address_province;
        $company_tin = str_split($data['company']->tin);
        $company_zip_code = ($data['company']->zip_code) ? str_split($data['company']->zip_code) : str_split("0000");
        $company_address = $data['company']->street." ".$data['company']->brgy.", ".$data['company']->city.", ".$data['company']->province;

        $pdf = new Fpdi();
        $page_count = $pdf->setSourceFile(public_path("/bir-form/bir-2307.pdf"));
        for ($pageNo = 1; $pageNo <= $page_count; $pageNo++) {
            $tplIdx = $pdf->importPage($pageNo);
            $pdf->AddPage();
            $size = $pdf->getTemplateSize($tplIdx);
            $width = $size["width"];
            $height = $size["height"];
            $pdf->useTemplate($tplIdx, 5, 5, 205,280);
            if($pageNo == 1)
            {
                $pdf->SetFont('Times');
                $pdf->SetTextColor(0, 0, 0);
                $pdf->SetFontSize(10);
                $pdf->Text(57,41, $period_from_split[0]);
                $pdf->Text(61,41, $period_from_split[1]);
                $pdf->Text(66,41, $period_from_split[2]);
                $pdf->Text(70,41, $period_from_split[3]);
                $pdf->Text(74.5,41, $period_from_split[4]);
                $pdf->Text(79,41, $period_from_split[5]);
                $pdf->Text(83.5,41, $period_from_split[6]);
                $pdf->Text(87.5,41, $period_from_split[7]);
            }
        }

        // 用Laravel响应系统输出PDF,确保头信息正确
        return response()->stream(function() use ($pdf) {
            echo $pdf->Output('S'); // 'S'参数表示返回PDF字符串内容,而非直接输出
        }, 200, [
            'Content-Type' => 'application/pdf',
            'Content-Disposition' => 'inline; filename="direct_payment.pdf"'
        ]);
    }
}

关键说明

  • 放弃Livewire的AJAX请求:AJAX不适合处理文件下载场景,普通HTTP请求能让浏览器正确识别并处理PDF响应。
  • 控制器处理响应:通过Laravel的response()->stream()方法输出PDF,能精准设置Content-Type等头信息,避免FPDF直接输出导致的头冲突。
  • 参数传递:通过表单隐藏字段传递导出所需的关键ID,而非直接传递复杂数据结构,更安全高效。

内容的提问来源于stack exchange,提问作者Angel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 21:05:04