我的任务是使用auth头进行异步图像请求。我有这样的图像路径:角度4图像异步与承载头
<img src="{{file.src}}"/>
而且我需要添加持票人令牌头的这种请求。页面包含许多图像,所以Ajax请求不适合。 不知道该怎么做。
我的任务是使用auth头进行异步图像请求。我有这样的图像路径:角度4图像异步与承载头
<img src="{{file.src}}"/>
而且我需要添加持票人令牌头的这种请求。页面包含许多图像,所以Ajax请求不适合。 不知道该怎么做。
现在,没有办法通过html中的标签进行授权调用,浏览器不提供此API的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
}
});
});
}
}
在这里,去你的HTML:
<img [src]="('https://www.w3schools.com/css/trolltunga.jpg' | image) | async" />
我们用我们的管道来获得可观察到的一个base64字符串,并async
插入内src
实际发出的字符串标签。
如果你看看Network
选项卡里面,你会看到你的授权头是在XHR调用期间提供: 你需要记住 一件事是CORS:你的形象服务,服务器应该以一种方式配置,即它接受XHR对Angular应用程序运行的域名图像的调用,还需要为自定义管道提供绝对路径,否则会向Angular应用程序的域本身发出请求。
这不适用于Angular 4.它必须使用HttpClient的已弃用版本? – Charles
如果您已经为api实现了HttpInterceptor,那么可以通过让拦截器处理标头来简化上面的Pipe代码。下面是使用HttpClient更新的版本。
@Pipe({
name: 'image',
})
export class ImagePipe implements PipeTransform {
constructor(
private http: HttpClient,
private config: ConfigProvider
) { }
transform(url: string) {
return this.http.get(url, {responseType: "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
}
});
});
}
}
`
这里是例子interceptor:
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private config: ConfigProvider) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authReq = req.clone({
setHeaders: {
Authorization: this.config.getAuthorization(),
'X-App-ClientId': this.config.authentication['X-App-ClientId']
}
});
return next.handle(authReq);
}
}
这不起作用。它必须使用HttpClient的已弃用版本,因为switchMap似乎不再存在,或者至少不会按原样编译。而且,它不承认在这里有一行有两个异步进程:http.get和readAsDataURL。 – Charles
假设你已经实施了HttpIntercepter添加标题,下面是实际做的工作(在角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() { }};
});
}
}
您这样使用:
<img [src]="'/api/image/42' | secure | async" />
以前的解决方案是非常严重的缺陷。我不能保证这是完美的,但它实际上已经过测试并为我工作。
你不能返回你从http.get获得的observable!我不知道为什么以前的解决方案假设你可以。 http.get的observable指示何时从服务器检索数据。但是,之后还有另一个异步进程需要完成:调用reader.readAsDataURL。因此,您需要创建一个Observable,然后在该过程完成后再调用它。另外,如果您不立即将某些内容放入图像中,浏览器仍然会尝试使用HTTP加载图像,并且在JavaScript控制台中出现错误。这是第一位观察者的原因。接下来的电话会放入一张空白的小GIF图像。
这种方法的一个问题是,如果图像被多次使用,它会每次加载每一个图像。即使浏览器缓存,您每次都会转换为base64。我创建了一个缓存来存储图像,以便在第一个之后不再需要将来的查询。
为什么你认为XHR-s不适合这个? –
@JánHalaša - 你是什么意思?我认为可能在Angular 4中存在这个问题的一些默认的东西,我的意思是Resful API项目 –