То, что я пытаюсь достичь: у меня есть служебный метод, который генерирует PDF/CSV
на моем бэкэнде, и я хочу сохранить этот pdf, нажав кнопку на моем веб-интерфейсе.
Моей первой попыткой было создатьфайл и отправить целое PDF/CSV
контроллером.
@PostMapping(value = "/export")
public File exportReport(
@RequestParam(value = "format", defaultValue = "PDF") ExportFileFormat format,
@RequestBody ExportBody exportBody) {
if (format.equals(ExportFormat.CSV)) {
return reportService.csvExportSummaryCustomerReport(exportBody);
}
if (format.equals(ExportFormat.PDF)) {
return reportService.pdfExportSummaryCustomerReport(exportBody);
}
throw new InvalidWorkingTimeSyntaxException(String.format("Format:%s is invalid.", format));
}
Но это решение дало мне ошибки с
Доступ к XMLHttpRequest в 'file: /// C: / Users/UserFolder/AppData/Local/Temp/csv6677594787854925068.csv 'from origin' http://localhost:4200' заблокирован политикой CORS: запросы перекрестного источника поддерживаются только для схем протоколов: http, data, chrome, chrome-extension, https.
Ofc Я пытался установить новый заголовок ответа set с помощью 'Access-Control-Allow-Origin' : '*'
, но это не помогло.То же самое с chrome.exe --allow-file-access-from-files --disable-web-security
.
. Поэтому я решил использовать другой подход, который заключается в передаче bytes[]
и создании углового файла PDF/CSV
.
@PostMapping(value = "/export")
public ResponseEntity<byte[]> exportReport(
@RequestParam(value = "format", defaultValue = "pdf") ExportFileFormat format,
@RequestBody ExportBody exportBody) {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("Access-Control-Allow-Origin", "*");
if (format.equals(ExportFileFormat.CSV)) {
responseHeaders.setContentType(MediaType.valueOf("text/csv"));
return new ResponseEntity<>(reportService.csvExportSummaryCustomerReport(exportBody),
responseHeaders,
HttpStatus.OK);
}
if (format.equals(ExportFileFormat.PDF)) {
responseHeaders.setContentType(MediaType.APPLICATION_PDF);
return new ResponseEntity<>(reportService.pdfExportSummaryCustomerReport(exportBody),
responseHeaders,
HttpStatus.OK);
}
throw new InvalidExportFileFormatException(String.format("Format:%s is invalid.", format));
}
Теперь я добавил заголовки и бэкэндкажется в порядке.После этого я создал сервис с фронтальной стороны:
exportReport(exportBody: ExportBody, format: String): Observable<Object> {
const exportUrl = `${this.reportsUrl}/export?format=${format}`;
if (format == "PDF") {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/pdf',
'Accept': 'application/pdf'
})
};
return this.http.post(exportUrl, exportBody, httpOptions);
}
if (format == "CSV") {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'text/csv',
'Accept': 'text/csv'
})
};
return this.http.post(exportUrl, exportBody, httpOptions);
}
}
Прямо сейчас я хотел использовать его только для печати результата.
downloadPdf() {
this.hoursWorkedForCustomersService.exportReport(this.exportBody, "PDF").subscribe(
result => {
console.log(result);
//saveAs(result, 'new.csv'); <- in the future.
}
);
}
Очевидно, что в будущем я хотел бы загрузить файл как PDF/CSV
, например,
saveAs(result, 'new.pdf');
У меня ошибка 406. Ответ:
POST http://localhost:4200/export?format=PDF 406.
TypeError: Cannot read property 'message' of null
at SafeSubscriber.next.handle.do.err [as _error] (error.interceptor.ts:25)
at SafeSubscriber.__tryOrSetError (Subscriber.js:240)
at SafeSubscriber.error (Subscriber.js:195)
at Subscriber._error (Subscriber.js:125)
at Subscriber.error (Subscriber.js:99)
at DoSubscriber._error (tap.js:84)
at DoSubscriber.error (Subscriber.js:99)
at XMLHttpRequest.onLoad (http.js:1825)
at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:4006)
Есть идеи, что я делаю не так?