首页 > 解决方案 > 使用 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

但没有运气。

我怎样才能解决这个问题?

标签: node.jsangularubuntunestjs

解决方案


如果您拥有 /var/www/ 可能会解决此问题

sudo chown -R $(whoami) /var/www/

推荐阅读