我的任務是使用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項目 –