从lambda函数nodejs + angular下载后Excel损坏

r3i60tvu  于 2023-05-17  发布在  Node.js
关注(0)|答案(1)|浏览(114)

我用Nodejs写了代码,生成Excel文件。然后将生成的文件转换为客户端请求。我正在从基于Angular 的前端提出请求。下面是完整的代码。我使用exceljs创建excel文件。

let [row] = await conn.execute(
            "Query",
            []
        );
        
        let abc = Object.keys(row[0]);
        
        var workbook = new excel.Workbook();
        var worksheet = workbook.addWorksheet('Sheet1');

        let clm = [];

        abc.forEach(element => {                
            clm.push({ header: element, key: element });
        });

        worksheet.columns = clm;

        worksheet.addRows(row);

        var tempFilePath = tempfile('.xlsx');
        workbook.xlsx.writeFile(tempFilePath).then(function () {

            res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
            res.setHeader("Content-Disposition", "attachment; filename=temp.xlsx");

            res.sendFile(tempFilePath, function (err) {
                // console.log('---------- error downloading file: ' + err);
            });

        });

这是我的angular代码。

reports(params: any): Observable<any> {
     
        return this.http.post(environment.apiUrl + '/reports', JSON.stringify(params), { responseType: 'arraybuffer' })
            .pipe(map((result) => {
                return result;
            }),
                catchError((err) => {
                    throw err;
                })
            );

    }

this.apicallService
      .reports(json)
      .subscribe(
        (result) => {
          
          var blob = new Blob([result], { type : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
          var link = document.createElement('a');
          link.href = URL.createObjectURL(blob);
          link.download = filename;
          link.click();
        },
        (err) => {
          this.notifyService.showError(err.message, 'Error');
        }
      );

以上代码在本地环境中运行良好。但是当我在aws lambda上发布代码时,excel文件正在下载,但它被损坏了。
我也从这个主题中引用了一些,但没有运气。
Corrupt XLSX file after downloading
我认为是API网关的问题。但我就是想不通。请提出解决办法。

vbkedwbf

vbkedwbf1#

在花了很多时间去理解这个问题之后,解决方案就出现了。所以问题是API网关和Lambda函数作为base64流而不是二进制流进行通信。这就是为什么我将响应转换为base64字符串并发送回客户端。
在客户端,我已经将base64字符串转换为Excel。下面是完整的代码。
Nodejs函数

let [row] = await conn.execute(
            Query",
            []
        );

        let abc = Object.keys(row[0]);

        var workbook = new excel.Workbook();
        var worksheet = workbook.addWorksheet('Sheet1');

        let clm = [];

        abc.forEach(element => {
            clm.push({ header: element, key: element });
        });

        worksheet.columns = clm;

        worksheet.addRows(row);

        const wbout = await workbook.xlsx.writeBuffer();
        
        res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        res.setHeader("Content-Disposition", "attachment; filename=temp.xlsx");
        res.isBase64Encoded = true;

        res.status(200).send(Buffer.from(wbout).toString('base64'));

Angular Code

return this.http.post(environment.apiUrl + '/reports', JSON.stringify(params), {responseType: 'text'})
        .pipe(map((result) => {
            return result;
        }),
            catchError((err) => {
                throw err;
            })
        );

this.apicallService
      .reports(json)
      .subscribe(
        (result) => {
          
          let blob = this.base64ToBlob(result, result.length);
          var link = document.createElement('a');
          link.href = URL.createObjectURL(blob);
          link.download = filename;
          link.click();

        },
        (err) => {
          this.notifyService.showError(err.message, 'Error');
        }
      );
      
      
      public base64ToBlob(b64Data: any, sliceSize = 512) {    
        let byteCharacters = atob(b64Data); //data.file there
        let byteArrays = [];
        for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
          let slice = byteCharacters.slice(offset, offset + sliceSize);

          let byteNumbers = new Array(slice.length);
          for (var i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
          }
          let byteArray = new Uint8Array(byteNumbers);
          byteArrays.push(byteArray);
        }
        return new Blob(byteArrays, { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
      }

这些是我引用的链接。
API gateway returning corrupted excel file https://www.serverless.com/framework/docs/providers/aws/events/apigateway#binary-media-typesAngular 4 -将base 64转换为可下载文件
谢谢大家。

相关问题