如何在TypeScript中创建图片类型校验方法?支持含动图的指定格式
TypeScript图片类型校验方法实现
针对你需要校验JPEG、GIF(含动态)、PNG、SVG、BMP格式图片的需求,这里提供几种不同可靠性级别的TypeScript实现方案,你可以根据场景选择:
1. 基础校验:文件扩展名校验
这种方式简单快速,但存在被篡改扩展名绕过的风险,适合对安全性要求不高的场景。
首先定义允许的扩展名集合,然后实现校验函数:
// 预定义允许的图片扩展名(统一转小写处理) const ALLOWED_IMAGE_EXTENSIONS = new Set(['.jpg', '.jpeg', '.gif', '.png', '.svg', '.bmp']); /** * 通过文件扩展名校验图片类型 * @param file 上传的File对象 * @returns 是否为合法图片类型 */ function validateImageByExtension(file: File): boolean { if (!file.name) return false; // 提取文件扩展名并转小写 const extension = `.${file.name.split('.').pop()?.toLowerCase() ?? ''}`; return ALLOWED_IMAGE_EXTENSIONS.has(extension); }
2. 可靠校验:MIME类型校验
利用File对象自带的type属性校验,比扩展名更可靠,但部分老旧环境或自定义文件可能存在type为空的情况。
// 预定义允许的图片MIME类型 const ALLOWED_IMAGE_MIME_TYPES = new Set([ 'image/jpeg', 'image/gif', 'image/png', 'image/svg+xml', 'image/bmp' ]); /** * 通过MIME类型校验图片类型 * @param file 上传的File对象 * @returns 是否为合法图片类型 */ function validateImageByMimeType(file: File): boolean { return ALLOWED_IMAGE_MIME_TYPES.has(file.type); }
3. 双重校验:扩展名+MIME类型
结合两种方式,平衡安全性和兼容性,是大多数场景的最优选择:
/** * 双重校验图片类型,提升可靠性 * @param file 上传的File对象 * @returns 是否为合法图片类型 */ function validateImage(file: File): boolean { return validateImageByExtension(file) && validateImageByMimeType(file); }
4. 严格校验:文件头校验(防篡改)
如果需要最高级别的安全性(防止用户修改扩展名和MIME类型绕过校验),可以读取文件的二进制头信息判断真实类型:
/** * 通过文件二进制头校验真实图片类型(异步方法) * @param file 上传的File对象 * @returns Promise<boolean> 是否为合法图片类型 */ async function validateImageByFileHeader(file: File): Promise<boolean> { return new Promise((resolve) => { const reader = new FileReader(); reader.onload = (e) => { const arrayBuffer = e.target?.result as ArrayBuffer; const uint8Array = new Uint8Array(arrayBuffer); // 读取文件前4字节用于判断类型 const headerHex = Array.from(uint8Array.subarray(0, 4)) .map(byte => byte.toString(16).padStart(2, '0')) .join('') .toUpperCase(); let isValid = false; // 匹配各图片类型的文件头特征 switch (true) { case headerHex.startsWith('FFD8FF'): // JPEG case headerHex.startsWith('47494638'): // GIF(含动态GIF) case headerHex.startsWith('89504E47'): // PNG case headerHex.startsWith('424D'): // BMP isValid = true; resolve(isValid); break; case file.type === 'image/svg+xml': // SVG为文本格式,单独处理 const textReader = new FileReader(); textReader.onload = (textEvent) => { const content = textEvent.target?.result as string; // 判断内容开头是否为SVG标签 resolve(content.trimStart().startsWith('<svg')); }; textReader.readAsText(file); break; default: resolve(false); } }; reader.onerror = () => resolve(false); // 仅读取文件前4字节,避免性能开销 reader.readAsArrayBuffer(file.slice(0, 4)); }); }
示例用法
在React文件上传组件中的使用示例:
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => { const file = event.target.files?.[0]; if (!file) return; // 根据需求选择校验方法 if (validateImage(file)) { console.log('图片类型合法,可执行上传逻辑'); // 这里写你的上传代码 } else { alert('仅允许上传JPEG、GIF、PNG、SVG、BMP格式的图片'); } // 如果使用严格校验: // try { // const isValid = await validateImageByFileHeader(file); // isValid ? console.log('类型合法') : alert('图片格式不合法'); // } catch (err) { // console.error('校验失败:', err); // } };
内容的提问来源于stack exchange,提问作者Nicholas Ribeiro
相关产品推荐
相关产品推荐

