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

使用pdf.js实现PDF缩放时出现Invalid page request错误求助

问题描述

我用pdf.js实现PDF放大缩小功能,以下是渲染/重渲染PDF的函数:

const renderPdfPage = async (pdf: any, pdfJS: any, pageNum: number) => {
        if (!canvasRef || !canvasRef.current) return;
        const docCavas = document.getElementById("the-canvas" + pageNum);
        if (!docCavas) {
            const el = window.document.createElement("canvas") as HTMLCanvasElement;
            el.id = "the-canvas" + pageNum;
            canvasRef.current.append(el);
        }
        if(pageNum > pdf.numPages){
            return;
        }
        const page = await pdf.getPage(pageNum);
        const viewport = page.getViewport({
            scale: pdfScale
        });
        let canvas = document.getElementById('the-canvas' + pageNum) as HTMLCanvasElement;
        const canvasContext = canvas.getContext('2d');
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        const renderContext = { canvasContext, viewport };
        const renderTask = page.render(renderContext);
        renderTask.promise.then(function () {
            const textContent = page.getTextContent();
            return textContent;
        }).then(function (textContent: string) {
            const textLayer = document.querySelector(`.${styles.textLayer}`) as HTMLDivElement;
            if (!textLayer) return;
            textLayer.style.left = canvas.offsetLeft + 'px';
            textLayer.style.top = canvas.offsetTop + 'px';
            textLayer.style.height = canvas.offsetHeight + 'px';
            textLayer.style.width = canvas.offsetWidth + 'px';
            textLayer.style.setProperty('--scale-factor', pdfScale.toString());
            pdfJS.renderTextLayer({
                textContentSource: textContent,
                container: textLayer,
                viewport: viewport,
                textDivs: []
            });
        });
    }

现在遇到问题:有时候获取PDF页面失败,抛出错误:

api.js:2917 Uncaught (in promise) Error: Invalid page request.
    at WorkerTransport.getPage (api.js:2917:29)
    at PDFDocumentProxy.getPage (api.js:837:28)
    at renderPdfPage (Previewer.tsx:55:32)
    at getPage (Previewer.tsx:136:68)

错误来自const page = await pdf.getPage(pageNum);这行代码,检查后没找到原因。以下是缩放功能函数:

const handleZoomOut = async (pdfUrl: any) => {
        if (!pdfUrl) {
            return;
        }
        var zoomoutbutton = document.getElementById("zoomoutbutton") as HTMLButtonElement;
        zoomoutbutton.onclick = function () {
            if (pdfScale <= 0.25) {
                return;
            }
            setPdfScale(pdfScale - 0.25);
            displayPage(currentPdf, pageNum);
        }
    }

请问遗漏了什么?该怎么修复?


问题分析与修复方案

1. 补全页码边界判断

当前只判断了pageNum > pdf.numPages,但pdf.js的页码是从1开始的,若pageNum为0或负数,调用getPage必然抛出Invalid page request错误。修改判断逻辑:

if(pageNum < 1 || pageNum > pdf.numPages){
    return;
}

2. 校验PDF实例有效性

传入renderPdfPage的pdf(也就是currentPdf)可能已经被销毁或失效(比如PDF加载中断、组件重渲染后引用丢失),此时调用getPage也会报错。在函数开头加校验:

if (!pdf || pdf.destroyed) {
    return;
}

3. 修复缩放函数的状态同步问题

handleZoomOut里的pageNum可能是过时的状态值,比如组件重渲染后未同步更新,导致传入无效页码。建议:

  • 用React状态管理pageNum,确保点击缩放按钮时获取最新值;
  • 调用displayPage时,传入当前实际显示的页码,而非依赖外部变量。

4. 处理异步渲染的竞态问题

快速多次点击缩放按钮会触发多次渲染请求,前一个请求未完成时,后一个请求的状态已变化,可能导致页码请求失效。可以给渲染任务加取消逻辑:

// 定义变量保存当前渲染任务
let currentRenderTask = null;

const renderPdfPage = async (pdf: any, pdfJS: any, pageNum: number) => {
    // 取消之前未完成的渲染任务
    if (currentRenderTask) {
        currentRenderTask.cancel();
    }
    // ... 原有代码
    const renderTask = page.render(renderContext);
    currentRenderTask = renderTask;
    renderTask.promise.then(function () {
        currentRenderTask = null;
        // ... 原有代码
    }).catch(err => {
        // 忽略渲染取消的报错
        if (err.name !== 'RenderingCancelledException') {
            console.error(err);
        }
        currentRenderTask = null;
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:27:05