Angular 4图像异步与承载标头

Kat*_*eva 7 html bearer-token angular

我的任务是使用auth标头进行异步图像请求.我有像这样的图像路径:

<img src="{{file.src}}"/>
Run Code Online (Sandbox Code Playgroud)

我需要为此类请求添加承载令牌到标头.页面包含许多图像,因此ajax请求不适合.不知道该怎么做.

Cha*_*les 8

假设你已经实现了一个HttpIntercepter来添加标题,这里有一个实际工作的解决方案(在Angular 4中):

import { Pipe, PipeTransform } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Pipe({
  name: 'secure'
})
export class SecurePipe implements PipeTransform {

  constructor(private http: HttpClient) { }

  transform(url: string) {

    return new Observable<string>((observer) => {
      // This is a tiny blank image
      observer.next('data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==');

      // The next and error callbacks from the observer
      const {next, error} = observer;

      this.http.get(url, {responseType: 'blob'}).subscribe(response => {
        const reader = new FileReader();
        reader.readAsDataURL(response);
        reader.onloadend = function() {
          observer.next(reader.result);
        };
      });

      return {unsubscribe() {  }};
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

你这样使用它:

<img [src]="'/api/image/42' | secure | async" />
Run Code Online (Sandbox Code Playgroud)

以前的解决方案存在严重缺陷.我不保证这是完美的,但它实际上已经过测试并且适合我.

你无法返回从http.get获得的observable!我不知道为什么以前的解决方案假设你可以.http.get的observable指示何时从服务器检索数据.但是,还有另一个异步过程必须在此之后完成:对reader.readAsDataURL的调用.因此,您需要创建一个Observable,您将在该过程完成后接下来调用它.

此外,如果您没有立即在图像中添加某些内容,浏览器仍会尝试使用HTTP加载图像,并且您在JavaScript控制台中出现错误.这就是第一个观察到一个空的微小GIF图像的observer.next调用的原因.

这种方法的一个问题是,如果图像被多次使用,它将每次加载每个图像.即使浏览器缓存,您也会每次都转换为base64.我创建了一个存储图像的缓存,以便在第一个之后不需要将来的查询.


Arm*_*yan 5

现在,无法仅通过 html 中的标签进行 Authorized 调用,浏览器没有为此提供 API,因此您必须发出 XHR 请求。这是一个解决方法:通过 XHR 获取图像,将其转换为 blob,然后将 blob 转换为 base64 并将图像插入到标签的 src 中。该解决方案需要清除两个管道:一个是用于进行 XHR 调用的自定义管道,另一个是 Angular 的内置管道async。这是我们的定制管道:

import { Pipe, PipeTransform } from '@angular/core';
import { Http, RequestOptions, Headers, ResponseContentType } from @angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';

@Pipe({name: 'image'})
export class ImagePipe implements PipeTransform {
  constructor(private http: Http) {}

  transform(url: string) {
  const headers = new Headers({'Authorization': 'MY TOKEN', 'Content-Type': 'image/*'}); /* tell that XHR is going to receive an image as response, so it can be then converted to blob, and also provide your token in a way that your server expects */
  return this.http.get(url, new RequestOptions({headers: headers, responseType: ResponseContentType.Blob})) // specify that response should be treated as blob data
  .map(response => response.blob()) // take the blob
  .switchMap(blob => {
  // return new observable which emits a base64 string when blob is converted to base64
      return Observable.create(observer => { 
        const  reader = new FileReader(); 
        reader.readAsDataURL(blob); // convert blob to base64
        reader.onloadend = function() {             
              observer.next(reader.result); // emit the base64 string result
        }
      });
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

这是你的html:

<img [src]="('https://www.w3schools.com/css/trolltunga.jpg' | image) | async" />
Run Code Online (Sandbox Code Playgroud)

我们使用管道获取 base64 字符串的 observable,并将async实际发出的字符串插入src标签内。

如果您查看Network选项卡内部,您将看到在 XHR 调用期间提供了您的 Authorization 标头: 在此处输入图片说明 您需要记住的一件事是 CORS:您的图像服务服务器应配置为接受来自运行 Angular 应用程序的域的图像的 XHR 调用,此外,您必须提供自定义的绝对 url管道,否则它将向 Angular 应用程序的域本身发出请求。