HTTP-запрос от Angular до Docker Engine API (вывод выполнения - изображение извлечения) - PullRequest
1 голос
/ 03 марта 2020

Я пишу Angular приложение для управления docker контейнерами / изображениями и т. Д. c.

. Docker Engine Api v1.39 доступен по HTTP .

Возникла проблема с http-запросом "pull a image" (документация здесь) .

Я не хочу извлекать (загружать) изображение и отображать результаты выполнения в моем приложении angular. Я создал запрос с curl, который отлично работает и выводит прогресс на стандартный вывод. С angular я не могу получить прогресс.

Запрос curl:

curl -u пользователь: pass -X POST "http://192.168.1.3: 2376 / v1.39 / images / create? FromImage = 10.0.149.224: 5000/500: 0280"

Вывод:

{"status":"Pulling from 500","id":"0280"}
{"status":"Pulling fs layer","progressDetail":{},"id":"e12b1fe81418"}
{"status":"Downloading","progressDetail":{"current":534865,"total":1690342827},"progress":"[\u003e                                                  ]  534.9kB/1.69GB","id":"e12b1fe81418"}
{"status":"Downloading","progressDetail":{"current":8221841,"total":1690342827},"progress":"[\u003e                                                  ]  8.222MB/1.69GB","id":"e12b1fe81418"}
{"status":"Downloading","progressDetail":{"current":17691793,"total":1690342827},"progress":"[\u003e                                                  ]  17.69MB/1.69GB","id":"e12b1fe81418"}
{"status":"Downloading","progressDetail":{"current":26023889,"total":1690342827},"progress":"[\u003e                                                  ]  26.02MB/1.69GB","id":"e12b1fe81418"}
{"status":"Downloading","progressDetail":{"current":34936785,"total":1690342827},"progress":"[=\u003e                                                 ]  34.94MB/1.69GB","id":"e12b1fe81418"}
....
....
{"status":"Pull complete","progressDetail":{},"id":"e12b1fe81418"}
{"status":"Digest: sha256:d3d30b514d3592e6df8d3196e365ef1a5128f6a20747a87a889f8de673da476a"}

Angular:

registry.service.ts

  public downloadImage(): Observable<HttpEvent<any>> {

    const req = new HttpRequest('POST', `http://192.168.1.3:2376/v1.39/images/create?fromImage=10.0.149.224:5000/500:0280`, {
      reportProgress: true
    });

    return this.http.request(req);
  }

registry.component.ts

public downloadImage(): void {
    this.dockerRegistryService.downloadImage()
    .subscribe(event => {

      // progress
      if (event.type === HttpEventType.DownloadProgress) {
        // console.log(event, event);
        // event.loaded = bytes transfered
        // event.total = "Content-Length", set by the server
        // const percentage = 100 / event.total * event.loaded;
        // console.log(percentage);
        console.log('event');
      }

      // finished
      if (event.type === HttpEventType.Response) {
        console.log(event.body);
      }

    });

Вывод: полный журнал @pastebin (https://pastebin.com/uq8VQNa0)

ERROR 
HttpErrorResponse {headers: HttpHeaders, status: 200, statusText: "OK", url: "http://192.168.1.3:2376/v1.39/images/create?fromImage=10.0.149.224:5000/500:0280", ok: false, …}
headers: HttpHeaders
normalizedNames: Map(0)
[[Entries]]
No properties
size: (...)
__proto__: Map
lazyUpdate: null
lazyInit: () => {…}
__proto__: Object
status: 200
statusText: "OK"
url: "http://192.168.1.3:2376/v1.39/images/create?fromImage=10.0.149.224:5000/500:0280"
ok: false
name: "HttpErrorResponse"
message: "Http failure during parsing for http://192.168.1.3:2376/v1.39/images/create?fromImage=10.0.149.224:5000/500:0280"
error:
error: SyntaxError: Unexpected token { in JSON at position 43 at JSON.parse (<anonymous>) at XMLHttpRequest.onLoad (http://localhost:4200/vendor.js:37027:51) at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:413:35) at Object.onInvokeTask (http://localhost:4200/vendor.js:74235:33) at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:412:40) at Zone.runTask (http://localhost:4200/polyfills.js:181:51) at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:494:38) at invokeTask (http://localhost:4200/polyfills.js:1609:18) at XMLHttpRequest.globalZoneAwareCallback (http://localhost:4200/polyfills.js:1646:25)
stack: "SyntaxError: Unexpected token { in JSON at position 43↵    at JSON.parse (<anonymous>)↵    at XMLHttpRequest.onLoad (http://localhost:4200/vendor.js:37027:51)↵    at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:413:35)↵    at Object.onInvokeTask (http://localhost:4200/vendor.js:74235:33)↵    at ZoneDelegate.invokeTask (http://localhost:4200/polyfills.js:412:40)↵    at Zone.runTask (http://localhost:4200/polyfills.js:181:51)↵    at ZoneTask.invokeTask [as invoke] (http://localhost:4200/polyfills.js:494:38)↵    at invokeTask (http://localhost:4200/polyfills.js:1609:18)↵    at XMLHttpRequest.globalZoneAwareCallback (http://localhost:4200/polyfills.js:1646:25)"
message: "Unexpected token { in JSON at position 43"
__proto__: Error
constructor: ƒ SyntaxError()
name: "SyntaxError"
message: ""
toString: ƒ toString()
__proto__: Object
text: "{"status":"Pulling from 500","id":"0280"}
↵{"status":"Pulling fs layer","progressDetail":{},"id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":547177,"total":1690342827},"progress":"[\u003e                                                  ]  547.2kB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":5529697,"total":1690342827},"progress":"[\u003e                                                  ]   5.53MB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":12214369,"total":1690342827},"progress":"[\u003e                                                  ]  12.21MB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":20570209,"total":1690342827},"progress":"[\u003e                                                  ]  20.57MB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":30583673,"total":1690342827},"progress":"[\u003e                                                  ]  30.58MB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":40053625,"total":1690342827},"progress":"[=\u003e                                                 ]  40.05MB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":47295353,"total":1690342827},"progress":"[=\u003e                                                 ]   47.3MB/1.69GB","id":"e12b1fe81418"}
↵{"status":"Downloading","progressDetail":{"current":57879417,"total":1690342827},"progress":"[=\u003e                                                 ...
....
....
↵{"status":"Digest: sha256:d3d30b514d3592e6df8d3196e365ef1a5128f6a20747a87a889f8de673da476a"}
↵{"status":"Status: Downloaded newer image for 10.0.149.224:5000/500:0280"}
↵"
__proto__: Object
__proto__: HttpResponseBase

HTTP-запрос «работает» (он тянет изображение и статус 200), но запрос делает не распознает никаких событий и не выдает никаких результатов при извлечении изображения. Он просто возвращается, когда весь запрос завершен, и возникает ошибка, когда http-клиент пытается проанализировать несколько json возвратов.

Обновление: Попытка с XMLHttpRequest: Это мое в первый раз работая с XMLHttpRequest, так что, возможно, я сделал что-то не так. Прочитав немного, я попытался вернуть Observable с «XHR» внутри обратного вызова. Но это тоже не работает. Моя наблюдаемая не изменится, пока не закончится полная загрузка.

registry.service.ts

public downloadImage(): Observable<Object[]> {

      return Observable.create(observer => {
      const xhr = new XMLHttpRequest();
      xhr.open('POST', `http://192.168.1.3:2376/v1.39/images/create?fromImage=10.0.149.224:5000/500:0280`, true);
      xhr.onprogress = () => {
        observer.next();
        console.log('test');
      };
      xhr.onreadystatechange =  (Evt) => {
        if (xhr.readyState === 3) {
          observer.next();
          console.log('progress');
      }

        if (xhr.readyState === 4) {
            observer.complete();
            console.log('finished');
        }
      };
      xhr.send();
    });      
}
...