Pour une application Web, j'ai besoin d'obtenir mes images avec une demande ajax car nous avons la signature + l'authentification sur notre API, donc nous ne pouvons pas obtenir d'images en utilisant un simple <img src="myapi/example/145"/>
Puisque nous utilisons angular2, nous avons évidemment cherché un blob ou quelque chose comme ça, mais comme indiqué dans le fichier static_response.d.ts
:
/**
* Not yet implemented
*/
blob(): any;
Alors d'accord, je ne peux pas le faire pour l'instant, je dois attendre que cette fonctionnalité soit implémentée.
Mais le problème est que je ne peux pas attendre, j'ai donc besoin d'un correctif ou d'un petit hack pour pouvoir obtenir les données d'image de la réponse et je pourrai supprimer mon hack et définir l'appel de la méthode blob()
sur bon quand il sera mis en œuvre.
J'ai essayé ceci:
export class AppComponent {
constructor(private api:ApiService, private logger:Logger){}
title = 'Tests api';
src='http://placekitten.com/500/200'; //this is src attribute of my test image
onClick(){ //Called when I click on "test" button
this.api.test().then(res => {
console.log(res._body);
var blob = new Blob([new Uint8Array(res._body)],{
type: res.headers.get("Content-Type")
});
var urlCreator = window.URL;
this.src = urlCreator.createObjectURL(blob);
});
}
}
avec la méthode ApiService.test()
:
test():Promise<any> {
return this.http.get(this._baseUrl + "myapi/example/145", this.getOptions())
//getOptions() is just creating three custom headers for
//authentication and CSRF protection using signature
.toPromise()
.then(res => {
this.logger.debug(res);
if(res.headers.get("Content-Type").startsWith("image/")){
return res;
}
return res.json();
})
.catch(res => {
this.logger.error(res);
return res.json();
} );
}
Mais je n'en tire aucune image et l'enregistrement des données de réponse montre une grosse chaîne qui est des données d'image.
Avez-vous un hack pour y parvenir?
Il n'est plus nécessaire d'étendre BrowserXhr
. (Testé avec angular 2.2.1) RequestOptionsArgs a maintenant une propriété responseType: ResponseContentType
qui peut être réglé sur ResponseContentType.Blob
Utilisation de DomSanitizer
import {DomSanitizer} from '@angular/platform-browser';
Cet exemple crée également une URL filtrée qui peut être liée à la propriété src
d'un <img>
this.http.get(url, {
headers: {'Content-Type': 'image/jpg'},
responseType: ResponseContentType.Blob
})
.map(res => {
return new Blob([res._body], {
type: res.headers.get("Content-Type")
});
})
.map(blob => {
var urlCreator = window.URL;
return this.sanitizer.bypassSecurityTrustUrl(urlCreator.createObjectURL(blob));
})
Utiliser le nouveau Angular HttpClient est vraiment facile à réaliser. En sortant de l'approche de tschuege, ce serait:
return this._http.get('/api/images/' + _id, {responseType: 'blob'}).map(blob => {
var urlCreator = window.URL;
return this._sanitizer.bypassSecurityTrustUrl(urlCreator.createObjectURL(blob));
})
La clé est de définir le responseType comme 'blob' afin qu'il ne tente pas de l'analyser en JSON
Je pense que vous avez manqué de définir le responseType
sur votre demande. Pour le moment, c'est un peu délicat car il n'est pas pris en charge.
La solution de contournement serait de remplacer la classe BrowserXhr
pour définir responseType
sur l'objet xhr
lui-même ...
Vous pouvez étendre le BrowserXhr
:
@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
constructor() {}
build(): any {
let xhr = super.build();
xhr.responseType = 'arraybuffer';
return <any>(xhr);
}
}
et remplacer le fournisseur BrowserXhr
par la classe étendue:
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);
Le problème est ici que vous ne remplacez pas toutes les demandes. Au niveau bootstrap, il remplacera tout. Vous pouvez donc le fournir dans un sous-injecteur dans l'attribut providers
du composant impacté ...
Voici un plunkr fonctionnel: https://plnkr.co/edit/tC8xD16zwZ1UoEojebkm?p=preview .