Мой стек: Angular 8, Node 12, Nest Js framework, сервер Ubuntu
Некоторый контекст: Я пытаюсь загрузить сгенерированный xlsx с сервера, у меня уже есть функциональная загрузка Excel, но она работает только тогда, когда я выполняю это методом GET, теперь мне нужно отправить некоторые параметры, поэтому я использую запрос POST. Этот код прекрасно работает на локальном хосте (In Windows 10)
У меня отказано в разрешении EACCESS, когда сервер пытается прочитать файл на временной основе.
Angular:
site-list.component.ts
onGetSitesXLSX(): void {
const ids = [];
this.dataSource.getSubject().subscribe(
sites => {
sites.forEach(s => ids.push(s._id));
this.siteService.downloadListF(ids)
.subscribe((res: Blob) => {
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const today = moment().format('MM-DD-YYYY hh-mm-ss');
importedSaveAs(blob, `List of sites ${today}.xlsx`);
}, error => {
if (error && error.error && error.error.message) {
this.downloadListError = SiteError.getErrorMessage(error.error.message);
}
});
}
);
}
site.service.ts
generateHeader(): { 'Content-Type': string, 'Authorization'?: string } {
return !!this.token ? {
'Content-Type': 'application/json',
Authorization: this.token
} : {
'Content-Type': 'application/json'
};
}
downloadListF(sites: string[]): Observable<Blob> {
const options = {
responseType: 'blob' as 'json',
headers: this.generateHeader(),
};
return this.http.post<Blob>(
this.apiURL + 'sites/filtered/xslx',
sites,
options
).pipe(
catchError(error => {
if (!!error && !!error.error && !!error.error.message && error.error.message === SiteErrorCode.unauthorized) {
this.coreService.newError(SiteError.getErrorMessage(SiteErrorCode.unauthorized));
}
return throwError(error);
}),
);
}
Серверная часть: site.controller.ts
@UseGuards(AuthGuard('jwt'), RolesGuard)
@Role(UserRole.guest)
@Post('filtered/xslx')
@ApiResponse({
status: 200,
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
})
@HttpCode(HttpStatus.OK)
@Header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
@Header('Content-Disposition', 'attachment; filename=message.xlsx')
async exportSitesFiltered(@Res() response, @Body()body) {
return response.sendFile(await this.exportSiteService.exportSiteListFiltered(body));
}
async exportSiteListFiltered(sitesIds): Promise<string> {
const sites = [];
let partial;
for (let id of sitesIds) {
partial = await this.siteService.getSiteById(id); // get populated data from DB
sites.push(partial);
}
const headers = [
'Name',
'Type',
'Latitude',
'Longitude',
'Region',
'Data',
];
const data = [];
for (const site of sites) {
data.push(ExportSiteService.generateSingleSheetRow(site)); // formats the obejct in an array
}
return await this.xlsxService.generateXlsx('sites', headers, data);
}
xlsx.service.ts
async generateXlsx(fileName: string, headers: string[], data): Promise<string> {
const sheetPath = join(__dirname, '..', '..', '..', 'temp', `${fileName}.xlsx`);
closeSync(openSync(sheetPath, 'w'));
await xlsxPopulate
.fromBlankAsync()
.then(workbook => {
const rangeContent = [];
rangeContent.push(headers);
for (const row of data) {
rangeContent.push(row);
}
workbook.sheet(0).name(fileName);
workbook.sheet(0).cell('A1').value(rangeContent);
workbook.sheet(0).row(1).style({
bold: true,
italic: true,
});
return workbook.toFileAsync(sheetPath);
})
.catch(error => {
Logger.error(error);
throw new InternalServerErrorException(XlsxError.writeXlsx);
});
return sheetPath;
}
}
Ошибки на сервере:
0|nec-dev | (node:20697) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
0|nec-dev | [Nest] 20697 - 04/16/2020, 2:15:58 PM [ExceptionsHandler] EACCES: permission denied, open '/var/www/my-project/server/temp/sites.xlsx' +60115ms
0|nec-dev | Error: EACCES: permission denied, open '/var/www/my-project/server/temp/sites.xlsx'
0|nec-dev | at Object.openSync (fs.js:454:3)
0|nec-dev | at XlsxService.generateXlsx (/var/www/my-project/server/src/_utils/xlsx/xlsx.service.ts:17:15)
0|nec-dev | at ExportSiteService.exportSiteListFiltered (/var/www/my-project/server/src/site/services/export-site.service.ts:91:35)
0|nec-dev | at processTicksAndRejections (internal/process/task_queues.js:89:5)
0|nec-dev | at SiteController.exportSitesFiltered (/var/www/my-project/server/src/site/site.controller.ts:93:30)
0|nec-dev | at /var/www/my-project/server/node_modules/@nestjs/core/router/router-execution-context.js:45:28
0|nec-dev | at /var/www/my-project/server/node_modules/@nestjs/core/router/router-proxy.js:8:17
ОШИБКИ на консоли навигатора:
POST https://xxxxx/api/v1/sites/filtered/xslx 500 (Internal Server Error)
{headers: h, status: 500, statusText: "Internal Server Error", url: "https://xxxx/api/v1/sites/filtered/xslx", ok: false, …}
headers: h {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
status: 500
statusText: "Internal Server Error"
url: "https://xxxxx/api/v1/sites/filtered/xslx"
ok: false
name: "HttpErrorResponse"
message: "Http failure response for https://xxxx/api/v1/sites/filtered/xslx: 500 Internal Server Error"
error: Blob {size: 52, type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}
__proto__: O
Я пытался выполнить npm с sudo, а также:
npm cache clean --force
sudo chown -R $(whoami) ~/.npm
Но без удачи.
Как я могу это исправить?