node.js - 使用 Angular 8 和 Nodejs 从 ubuntu 中的服务器使用 POST 方法下载 xlsx 时出现“EACCESS:权限被拒绝”问题
问题描述
我的堆栈: Angular 8、Node 12、NestJs 框架、Ubuntu 服务器
一些上下文: 我正在尝试从服务器下载生成的 xlsx,我已经有一个功能性的 excel 下载,但只有当我使用 GET 方法执行它时才有效,现在我需要发送一些参数,所以我使用的是 POST 请求。此代码在 localhost 上完美运行(在 Windows 10 中)
当服务器尝试读取临时文件时,我的 EACCESS 权限被拒绝。
角度:
站点列表.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);
}
});
}
);
}
站点.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
我尝试使用 sudo 执行 npm,并且还:
npm cache clean --force
sudo chown -R $(whoami) ~/.npm
但没有运气。
我怎样才能解决这个问题?
解决方案
如果您拥有 /var/www/ 可能会解决此问题
sudo chown -R $(whoami) /var/www/
推荐阅读
- android - Docker 中的 Gitlab Android 模拟器:“请确保 KVM 已正确安装且可用。”
- angular - Jasmine - 应始终在 spyon 函数中指定返回值?
- ruby-on-rails - 访问控制器中的表单字段值(Ruby on rails)
- javascript - 使用角度指令更改选定列表元素颜色
- elixir - 处理 Absinthe 中的异常
- java - LdapRepository 配置不匹配
- python-2.7 - 如何从excel中提取数据到网站
- sql - 如果值不存在则插入值 - ORACLE/Postgres
- jmeter-5.0 - 如何从jmeter中的json响应中获取最后一个id?
- python - jupyter notebook:下载为带有 iframe 的 html