Возможно ли создать Post запрос для скачивания файла с сайта написаного на Angular?

Есть сайт. С помощью интструмента разработчика и Postman отследил запрос который отправляется при нажатии на загрузку файла. в ответ получаю {"error":false,"status":200} то же самое происходит и при взаимодействии с UI. Но после этого срабатывает blob и файл скачивается. У меня, в лучшем случае сохраняется в файл {"error":false,"status":200}. JS Код запускаю через консоль разработчика в браузере.

файлы генерируются до 30 метров, если запускать через UI, то я вижу, что запрос отрабатывается не сразу. В моем же случае, я мгновенно получаю 200. Из чего делаю вывод, что дело в асинхронности выполнения, но завершить мысль не хватает знаний. Прошу подсказки.

let XHR = new XMLHttpRequest();
let data = {event_name:'file_save_as'};
let link = 'link';
XHR.open( 'POST', link, true );
XHR.responseType = 'blob';
XHR.setRequestHeader('x-csrf-bypass', 'yes');
XHR.setRequestHeader("accept", "application/json");
XHR.setRequestHeader("Content-Type", "application/json");


XHR.onload = function(e) {
  if (this.status == 200) {
      // Create a new Blob object using the 
      //response data of the onload object
      var blob = new Blob([this.response], {type: 'application/json'});
      //Create a link element, hide it, direct 
      //it towards the blob, and then 'click' it programatically
      let a = document.createElement("a");
      a.style = "display: none";
      document.body.appendChild(a);
      //Create a DOMString representing the blob 
      //and point the link element towards it
      let url = window.URL.createObjectURL(blob);
      a.href = url;
      a.download = 'myFile.txt';
      //programatically click the link to trigger the download
      a.click();
      //release the reference to the file by revoking the Object URL
      window.URL.revokeObjectURL(url);
  }else{
      //deal with your error state here
  }
};

XHR.send(JSON.stringify(data));

Ответы (1 шт):

Автор решения: Дмитрий

Да, возможно. Подразумевается, что ваш бекенд готов принять POST запрос, обработать его и вернуть в ответ файл с соответствующими заголовками. Здесь опишу только пример решения на angular.

Для начала подготовим небольшой хук для отдачи файла клиенту. В верстке необходимо добавить:

<!-- ХУК -->
<a style="display: none" href="#" #downloadFile target="_blank"></a>

В компоненте вытащим данную ссылку:

@ViewChild('downloadFile') downloadFile: ElementRef;

Также у вас должны быть данные для POST запроса в виде

{field1: value1, field2: value2 ...}

Для этого я использую ReactiveFormsModule:

public form = new FormGroup({
  field1: new FormControl(null, []),
  field2: new FormControl(null, []),
});

Подробнее можно почитать в документации.

Подготовим сервис, который будет отправлять http запрос и возвращать содержимое файла

@Injectable({
  providedIn: 'root',
})
export class ExampleService {
  private downloadUrl = 'http://best-beckend.net/file';
  constructor(private http: HttpClient) {}

  public downloadFile(data): Observable<string> {
    return this.http
      .post<string>(this.downloadUrl, data, { responseType: 'blob' as 'json' });
  }
}

Далее, в компоненте мы напишем вызов метода сервиса и отдачу файла пользователю

downloadFile(): void {
  this.service.downloadFile(this.form.value)
  .pipe(takeUntil(this.unsubscribe$)) // Не забываем делать отписку
  .subscribe(file => {
    if (file) {
      if (navigator.msSaveOrOpenBlob) {
        navigator.msSaveOrOpenBlob(file, 'Имя файла.расширение файла');
      } else {
        const url = window.URL.createObjectURL(file);
        const link = this.downloadFile.nativeElement;
        link.href = url;
        link.download = 'Имя файла.расширение файла';
        link.click();

        window.URL.revokeObjectURL(url);
    }
  });
}
→ Ссылка