如何在Angular 2中判断服务端返回的Blob是PDF还是图片?
判断Blob内容是图片还是PDF的实用方案
我来给你几个实用的方案,帮你准确判断Blob里是图片还是PDF——毕竟直接硬设content-type确实容易踩坑,尤其是服务端没返回正确类型的时候:
方法一:通过文件头(Magic Number)判断(最准确)
每种文件格式都有独特的文件头标识(也就是常说的Magic Number),这个是最靠谱的判断依据,完全不受服务端返回的content-type影响。比如:
- PDF的文件头是
%PDF-(十六进制为25 50 44 46) - JPG的文件头是
FF D8 FF - PNG的文件头是
89 50 4E 47
你可以通过读取Blob的前几个字节来判断:
// 定义一个判断Blob类型的异步函数 function detectBlobType(blob: Blob): Promise<string> { return new Promise((resolve) => { const reader = new FileReader(); reader.onload = function(e) { // 读取Blob的前4个字节(足够判断常见的图片和PDF类型) const arrayBuffer = e.target?.result as ArrayBuffer; const uint8Array = new Uint8Array(arrayBuffer.slice(0, 4)); // 转成十六进制字符串,方便对比 const headerHex = Array.from(uint8Array) .map(byte => byte.toString(16).padStart(2, '0')) .join(''); // 根据文件头判断类型 if (headerHex.startsWith('25504446')) { resolve('application/pdf'); } else if (headerHex.startsWith('ffd8ff')) { resolve('image/jpeg'); } else if (headerHex.startsWith('89504e47')) { resolve('image/png'); } else if (headerHex.startsWith('47494638')) { resolve('image/gif'); } else { // 未知类型的话,返回Blob原本的type或者标记为unknown resolve(blob.type || 'unknown'); } }; // 只读取前4个字节,节省资源 reader.readAsArrayBuffer(blob.slice(0, 4)); }); }
方法二:用Image对象尝试加载(简单直观)
如果你的场景里只有图片和PDF两种可能,可以尝试用浏览器的Image对象加载Blob:图片能正常加载,PDF则会触发错误。
function isImageBlob(blob: Blob): Promise<boolean> { return new Promise((resolve) => { const img = new Image(); img.onload = () => { resolve(true); // 记得释放URL,避免内存泄漏 URL.revokeObjectURL(img.src); }; img.onerror = () => { resolve(false); URL.revokeObjectURL(img.src); }; img.src = URL.createObjectURL(blob); }); }
这个方法的缺点是:如果Blob是损坏的图片,可能会误判成PDF,所以更适合作为辅助判断手段,或者和方法一结合使用。
结合到你的Angular代码里
你可以在downloadPDF方法中,用RxJS的switchMap把Blob流转换成带正确类型的Blob:
import { from } from 'rxjs'; import { switchMap, map } from 'rxjs/operators'; downloadPDF(fileId: string): Observable<Blob> { const header = new HttpHeaders().append('Accept', 'application/octet-stream'); return this._http.get(this._api.powerLoadApi.getFileLink(this.WellId, fileId), { headers: header, responseType: 'blob', }).pipe( switchMap(res => { // 调用前面的detectBlobType函数,把Promise转成Observable return from(detectBlobType(res)).pipe( map(detectedType => { // 创建新的Blob,设置正确的content-type return new Blob([res], { type: detectedType }); }) ); }) ); }
额外提醒
如果服务端能在响应头里返回正确的Content-Type,那优先用这个值更省心:
// 在http.get的pipe里可以先读取响应头 .pipe( tap(res => { const contentType = res.headers.get('Content-Type'); console.log('服务端返回的类型:', contentType); }) )
只有当服务端返回的是application/octet-stream或者类型不正确时,再用上面的判断方法。
内容的提问来源于stack exchange,提问作者Tishman
相关产品推荐
相关产品推荐

