Ionic3中ngIf结合async管道使用出现404错误的原因排查
咱们来一步步拆解这个问题:
首先,你遇到的GET http://localhost:8100/null错误,核心原因有两个:
1. 多次async订阅导致的数据流不同步
你在第一个代码里用了两次(imgDoc$ | async):一次在*ngIf的条件判断里,一次在img的[src]绑定里。
Angular的async管道每次使用都会对Observable创建一个新订阅。如果imgDoc$是一个冷Observable(比如从HTTP请求、Firestore这类数据源来的),这就会触发两次独立的数据获取操作。这两次订阅的数据流可能不同步:比如第一次订阅还在加载等待返回值时,第二次订阅先返回了null/undefined,此时*ngIf的条件刚好变为true,img标签被渲染,src就被设置成了null,浏览器会把null当作相对路径发起请求,自然就出现404错误。
而第二个代码里只使用了一次async订阅,只会触发一次数据获取,当数据返回后src会被正确设置,不会出现中间状态的null请求。
2. *ngIf语法使用错误
你原本以为<p>No Image</p>是else块的内容,但实际上Angular的*ngIf+then语法规则是:当使用then指定模板时,宿主元素内部的内容会被完全忽略,不会被当作else块渲染。也就是说,你的代码里当条件不满足时,不会显示<p>No Image</p>,反而可能出现意料之外的渲染逻辑。
修复后的代码示例
方案1:用as语法避免多次订阅(推荐)
只订阅一次imgDoc$,把结果赋值给变量后复用,同时正确实现else逻辑:
<div *ngIf="imgDoc$ | async as imgDoc"> <ng-container *ngIf="imgDoc.photoURL; else NoImageContainer"> <img [src]="imgDoc.photoURL"/> Image Display </ng-container> </div> <ng-template #NoImageContainer> <p>No Image</p> </ng-template>
方案2:改进then语法的正确写法
同样通过as语法复用订阅结果,确保只订阅一次:
<ng-container *ngIf="(imgDoc$ | async)?.photoURL as photoURL; then DisplayImgContainer else NoImageContainer"></ng-container> <ng-template #DisplayImgContainer> <img [src]="photoURL"/> Image Display </ng-template> <ng-template #NoImageContainer> <p>No Image</p> </ng-template>
这两种写法都能避免多次订阅的问题,同时正确实现“有图显示图片,无图显示提示”的逻辑,不会再出现GET null的404错误。
内容的提问来源于stack exchange,提问作者Juliano JC

