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

ASP.NET Core中QuestPDF无法在浏览器新标签页打开PDF求助

解决方案:在浏览器新标签页打开QuestPDF生成的PDF

要实现后端生成PDF后直接在浏览器新标签页打开(而非本地阅读器或无反应),核心是将PDF字节流返回给前端,并通过HTTP响应头控制浏览器的处理行为。以下是具体实现步骤:


1. 重构PDF生成逻辑,返回字节数组

放弃QuestPDF的.GeneratePdfAndShow()(仅适用于桌面程序,会在服务器端调用本地阅读器),改用.GeneratePdf()生成字节数组,以便返回给前端。

修改你的Print方法:

public byte[] Print(string area, UserCST userCST, string name, List<object> kanbanOBJS)
{
    var document = Document.Create(container =>
    {
        container.Page(page =>
        {
            page.Content().Column(column =>
            {
                // 保留你原有的PDF内容构造逻辑,包括表格部分
                column.Item()
                    .PaddingTop(3)
                    .Table(table =>
                    {
                        table.ColumnsDefinition(columns =>
                        {
                            columns.RelativeColumn();
                            columns.RelativeColumn();
                            columns.RelativeColumn();
                            columns.RelativeColumn();
                            columns.RelativeColumn();
                        });
                        table.Header(header =>
                        {
                            header.Cell()
                                .Border(6, unit: Unit.Mil)
                                .AlignCenter()
                                .AlignMiddle()
                                .Text("LCCST_Position");
                            header.Cell()
                                .Border(6, unit: Unit.Mil)
                                .AlignCenter()
                                .AlignMiddle()
                                .Text("Pagoda Place");
                            header.Cell()
                                .Border(6, unit: Unit.Mil)
                                .AlignCenter()
                                .AlignMiddle()
                                .Text("Leadset");
                            header.Cell()
                                .Border(6, unit: Unit.Mil)
                                .AlignCenter()
                                .AlignMiddle()
                                .Text("Quantity of Bundles");
                            header.Cell()
                                .Border(6, unit: Unit.Mil)
                                .AlignCenter()
                                .AlignMiddle()
                                .Text("Commisioned?");
                        });
                        foreach (var item in kanbanOBJS)
                        {
                            dynamic obj = item;
                            table.Cell()
                                .AlignCenter()
                                .AlignMiddle()
                                .Text($"{obj.LCCST_Position}");
                            table.Cell()
                                .AlignCenter()
                                .AlignMiddle()
                                .Text($"{obj.PagodaPlace}");
                            table.Cell()
                                .AlignCenter()
                                .AlignMiddle()
                                .Text($"{obj.Leadset}");
                            table.Cell()
                                .AlignCenter()
                                .AlignMiddle()
                                .Text($"{obj.QtyOfBundles}");
                            table.Cell()
                                .AlignCenter()
                                .AlignMiddle()
                                .Text("");
                        }
                    });
            });
        });
    });

    // 生成PDF字节数组并返回
    return document.GeneratePdf();
}

2. 创建Controller Action返回PDF流

在你的Controller中添加一个Action,负责接收参数、生成PDF,并返回带有正确响应头的文件流:

public IActionResult GenerateKanbanPdf(string area, string name, int[] kanbanItemIds)
{
    // 1. 根据参数获取需要的Kanban数据(和你原有的逻辑一致)
    var newKanbanItems = _db.KanbanItems.Where(x => kanbanItemIds.Contains(x.Id)).ToList();
    List<object> kanbanOBJS = new List<object>();
    
    foreach (var item in newKanbanItems) 
    {
        int position = _db.ListContentCST.FirstOrDefault(x => x.LCCST_Id == item.KL_ListContentId).LCCST_Position;
        var kanbanOBJ = new
        {
            LCCST_Position = position,
            PagodaPlace = item.KL_PagodaPlace,
            Leadset = item.KL_Material,
            QtyOfBundles = item.KL_QtyOfBundles
        };
        kanbanOBJS.Add(kanbanOBJ);
    }

    // 2. 获取当前用户信息(根据你的实际认证方式调整)
    var userCST = HttpContext.Session.Get<UserCST>("CurrentUser");
    
    // 3. 生成PDF字节流
    var pdfBytes = Print(area, userCST, name, kanbanOBJS);

    // 4. 设置响应头:inline表示浏览器直接打开,而非下载
    return File(
        fileContents: pdfBytes,
        contentType: "application/pdf",
        fileDownloadName: "Kanban.pdf",
        enableRangeProcessing: true
    );
}

3. 前端触发PDF打开

通过前端按钮或链接,在新标签页请求上述Action:

方式1:直接跳转(适用于参数较少的场景)

<a href="/YourController/GenerateKanbanPdf?area=Production&name=ShiftA&kanbanItemIds=1,2,3" target="_blank">打开PDF</a>

方式2:POST请求(适用于参数较多或敏感数据场景)

document.getElementById("printKanbanBtn").addEventListener("click", async () => {
    const response = await fetch("/YourController/GenerateKanbanPdf", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "RequestVerificationToken": document.querySelector('input[name="__RequestVerificationToken"]').value
        },
        body: JSON.stringify({
            area: "Production",
            name: "ShiftA",
            kanbanItemIds: [1,2,3]
        })
    });

    const blob = await response.blob();
    const pdfUrl = URL.createObjectURL(blob);
    
    // 在新标签页打开PDF
    window.open(pdfUrl, "_blank");
    
    // 10秒后释放Blob URL,避免内存泄漏
    setTimeout(() => URL.revokeObjectURL(pdfUrl), 10000);
});

关键说明

  • .GeneratePdfAndShow()仅适用于桌面应用,会在服务器端启动本地PDF阅读器,完全不适合Web场景。
  • .GeneratePdf()只生成字节流,必须将其返回给前端才能被浏览器处理。
  • Content-Disposition设置为inline是核心,它告诉浏览器直接打开PDF而非触发下载。
  • 如果需要自动触发打印,可在新标签页打开PDF后调用window.print(),但后端无法直接触发客户端打印,必须依赖前端JS。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 09:46:28