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

Angular 17自定义Observable实现文件上传验证遇阻

解决Angular 17中文件MIME类型验证的两个问题

问题1:Observable.create 废弃替代

你已经用 new Observable() 替代了废弃的 Observable.create(),这是正确的做法——RxJS 现在推荐直接使用 Observable 构造函数来创建自定义流,不用再纠结废弃的 API 了。

问题2:null 类型不匹配

原来的返回类型和 Observer 类型只允许 { [key: string]: any } 类型的值,但验证通过时我们需要返回 null(表示没有验证错误),所以需要把类型扩展为包含 null 的联合类型。

修改后的完整代码

import { AbstractControl } from '@angular/forms';
import { Observable, Observer } from 'rxjs';

export const mimeType = (
  control: AbstractControl
): Promise<{ [key: string]: any } | null> | Observable<{ [key: string]: any } | null> => {
  const file = control.value as File;
  const filereader = new FileReader();

  // 调整Observer类型,允许null值
  return new Observable((observer: Observer<{ [key: string]: any } | null>) => {
    // 处理文件读取完成事件
    const onLoadEnd = () => {
      const arr = new Uint8Array(filereader.result as ArrayBuffer).subarray(0, 4);
      let header = '';
      let isValid = false;

      for (let i = 0; i < arr.length; i++) {
        header += arr[i].toString(16);
      }

      // 修正PNG头(原代码少了最后一位7,可选调整)
      switch (header) {
        case '89504e47':
          isValid = true;
          break;
        case 'ffd8ffe0':
        case 'ffd8ffe1':
        case 'ffd8ffe2':
        case 'ffd8ffe3':
        case 'ffd8ffe8':
          isValid = true;
          break;
        default:
          isValid = false;
          break;
      }

      if (isValid) {
        observer.next(null);
      } else {
        observer.next({ invalidMimeType: true });
      }
      observer.complete();
    };

    // 处理文件读取错误
    const onError = () => {
      observer.error('文件读取失败');
      observer.complete();
    };

    filereader.addEventListener('loadend', onLoadEnd);
    filereader.addEventListener('error', onError);

    filereader.readAsArrayBuffer(file);

    // 返回清理函数,移除事件监听避免内存泄漏
    return () => {
      filereader.removeEventListener('loadend', onLoadEnd);
      filereader.removeEventListener('error', onError);
    };
  });
};

关键修改点说明

  1. 类型调整:把返回类型和 Observer 类型都改成 { [key: string]: any } | null,这样 observer.next(null) 就符合类型要求了。
  2. 错误处理:新增了 error 事件监听,避免文件读取失败时流一直处于挂起状态。
  3. 内存泄漏防护:添加了清理函数,在 Observable 取消订阅时移除 FileReader 的事件监听,这是自定义 Observable 的最佳实践。
  4. 可选修正:原代码中 PNG 文件头写的是 '89504E4',正确的 PNG 文件头应该是 '89504e47'(对应十六进制的 89 50 4E 47),建议修正这个小问题以确保PNG文件验证准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 16:20:17