Получить изображение или байтовые данные с http

Для веб-приложения мне нужно получить мои изображения с помощью запроса ajax, потому что у нас есть подпись + аутентификация в нашем API, поэтому мы не можем получить изображения с помощью простого <img src="myapi/example/145"/>

Поскольку мы используем angular2, мы явно искали blob или что-то в этом роде, но, как указано в static_response.d.ts файл:

/**
 * Not yet implemented
 */
blob(): any;

Итак, пока я не могу сделать это, я должен ждать, пока эта функция будет реализована.

Но проблема в том, что я не могу ждать, поэтому мне нужно исправление или небольшой взлом, чтобы иметь возможность получить данные изображения из ответа, и я смогу удалить свой взлом и установить blob() вызов метода будет хорош, когда он будет реализован.

Я попробовал это:

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

с 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();
            } );
    }

Но я не получаю никакого изображения от него, и регистрация данных ответа показывает большую строку, которая является данными изображения.

У вас есть хак для достижения этой цели?

4 ответа

Решение

Не надо расширять BrowserXhr больше. (Протестировано с угловым 2.2.1) У RequestOptionsArgs теперь есть свойство responseType: ResponseContentType который может быть установлен на ResponseContentType.Blob

Использование DomSanitizer

import {DomSanitizer} from '@angular/platform-browser';

В этом примере также создается очищенная ссылка, которая может быть связана с src свойство <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));
        })

Используя новый Angular HttpClient действительно легко добиться этого. Исходя из подхода Чуеге, это будет:

return this._http.get('/api/images/' + _id, {responseType: 'blob'}).map(blob => {
  var urlCreator = window.URL;
  return this._sanitizer.bypassSecurityTrustUrl(urlCreator.createObjectURL(blob));
})

Ключ должен установить responseType как 'blob', чтобы он не пытался анализировать его как JSON

Я думаю, что вы пропустили, чтобы установить responseType по вашему запросу. Сейчас это немного сложно, потому что не поддерживается.

Обходной путь должен был бы переопределить BrowserXhr класс для установки responseType на xhr сам объект...

Вы могли бы продлить BrowserXhr:

@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
  constructor() {}
  build(): any {
    let xhr = super.build();
    xhr.responseType = 'arraybuffer';
    return <any>(xhr);
  }
}

и переопределить BrowserXhr провайдер с расширенным классом:

bootstrap(AppComponent, [
  HTTP_PROVIDERS,
  provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);

Проблема в том, что вы не переопределяете все запросы. На уровне начальной загрузки все будет отменено. Таким образом, вы могли бы предоставить его в субинжекторе внутри providers атрибут затронутого компонента...

Вот рабочий планер: https://plnkr.co/edit/tC8xD16zwZ1UoEojebkm?p=preview.

Этот JSFiddle может помочь вам: https://jsfiddle.net/virginieLGB/yy7Zs/936/

Метод, как вы и хотели, заключается в создании BLOB-объекта из предоставленного URL

// Image returned should be an ArrayBuffer.
var xhr = new XMLHttpRequest();

xhr.open( "GET", "https://placekitten.com/500/200", true );

// Ask for the result as an ArrayBuffer.
xhr.responseType = "arraybuffer";

xhr.onload = function( e ) {
    // Obtain a blob: URL for the image data.
    var arrayBufferView = new Uint8Array( this.response );
    var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
    var urlCreator = window.URL || window.webkitURL;
    var imageUrl = urlCreator.createObjectURL( blob );
    var img = document.querySelector( "#photo" );
    img.src = imageUrl;
};

xhr.send();
Другие вопросы по тегам