如何用JavaScript(Next.js)检测上传的PDF文件是否损坏?
验证损坏PDF的实现方案
基础校验:检查文件标准标识
PDF有固定的格式标识,先通过这个做初步过滤:
- 检查文件扩展名是否为
.pdf(作为基础拦截,避免非PDF文件) - 读取文件的前5字节,确认是
%PDF-(PDF标准文件头);读取文件末尾10字节,确认包含%%EOF(PDF标准文件尾)
深度校验:用专业库解析验证
基础校验可能漏过那些标识完整但内容损坏的PDF,这时候用pdfjs-dist(Mozilla官方的PDF解析库)尝试加载文件,解析失败则判定为损坏。
步骤1:安装依赖
npm install pdfjs-dist
步骤2:在Next.js客户端组件中实现逻辑
文件上传操作需在客户端完成,所以组件要加上'use client'指令:
'use client'; import { useState } from 'react'; import * as pdfjsLib from 'pdfjs-dist'; import 'pdfjs-dist/build/pdf.worker.min'; export default function PDFUploader() { const [error, setError] = useState(''); const handleFileChange = async (e) => { setError(''); const file = e.target.files[0]; if (!file) return; // 校验扩展名 if (!file.name.toLowerCase().endsWith('.pdf')) { setError('请上传PDF格式文件'); return; } const reader = new FileReader(); reader.onload = async (event) => { const arrayBuffer = event.target.result; const uint8Array = new Uint8Array(arrayBuffer); // 校验文件头 const header = new TextDecoder().decode(uint8Array.slice(0, 5)); if (header !== '%PDF-') { setError('文件不是有效的PDF'); return; } // 校验文件尾(允许末尾有换行等空白字符) const footer = new TextDecoder().decode(uint8Array.slice(-10)); if (!footer.includes('%%EOF')) { setError('文件不是有效的PDF'); return; } // 深度解析校验 try { const pdfDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; // 额外校验:确保至少有1个有效页面 if (pdfDoc.numPages < 1) { setError('损坏的PDF:无有效页面'); return; } // 校验通过,可执行后续上传逻辑 console.log('PDF验证通过'); } catch (err) { setError('损坏的PDF:无法解析内容'); } }; reader.readAsArrayBuffer(file); }; return ( <div> <input type="file" accept=".pdf" onChange={handleFileChange} /> {error && <p style={{ color: 'red' }}>{error}</p>} </div> ); }
注意事项
- 如果遇到worker加载失败问题,可手动指定worker地址:
pdfjsLib.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjsLib.version}/pdf.worker.min.js`; - 针对大文件,可优化头/尾读取逻辑,避免加载整个文件到内存。
内容的提问来源于stack exchange,提问作者Rômulo Valentim
相关产品推荐
相关产品推荐

