web-dev-qa-db-fra.com

Obtenez des données d'image ou d'octet avec http

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?

16
Supamiu

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));
        })
26
tschuege

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

9
Cuzox

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 .

4
Thierry Templier