如何使用带有Node/Express后端的Angular 5 HttpClient get方法下载Excel(xlsx)文件? [英] How to download an excel (xlsx) file using Angular 5 HttpClient get method with Node/Express backend?

查看:98
本文介绍了如何使用带有Node/Express后端的Angular 5 HttpClient get方法下载Excel(xlsx)文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的nodejs服务器上的目录中有一个excel文件-该文件的路径为-./api/uploads/appsecuritydesign/output/appsecdesign.xlsx

I have an excel file in a directory on my nodejs server - Path to the file is - ./api/uploads/appsecuritydesign/output/appsecdesign.xlsx

在Angular 5组件中单击一个按钮时,我只是试图使用FileSaver下载文件.

On click of a button in my Angular 5 component I am just trying to download the file using FileSaver.

下面是我的Angular组件.

Below is my Angular component.

这里是Angular中按钮的模板代码,一旦单击该代码将调用saveFile()函数.

Here the template code for the button in Angular that will call the saveFile() function once clicked.

<a class="btn btn-primary" (click) = "saveFile()">Download</a>

这是saveFile()函数.

Here is the saveFile() function.

   saveFile(){

    console.log("In ToolInput Component: ", this.token); //Okta token
          console.log("In ToolInput Component: ", this.whatamidoing); //this variable has the server FilePath

this.fileService.getappsecdesignfile(this.token, this.whatamidoing).subscribe(res => {
            let blobtool5 = new Blob([res], { type: 'application/vnd.ms-excel;charset=utf-8' });
            FileSaver.saveAs(blobtool5, 'Application_Security_Design.xlsx');
          },
          (err: HttpErrorResponse) => {
            if (err.error instanceof Error) {

                  console.log('An error occurred:', err.error.message);
                  console.log('Status', err.status);
                } else {
                  console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
                  console.log('Status', err.status);
                }
          });
    }

这时,我在浏览器中检查了console.log.他们正是他们应该做的.因此,我在fileService中将正确的文件路径和令牌传递给getappsecdesignfile方法.

At this point I checked the console.log in the browser. They are exactly what they are supposed to be. So I am passing the correct filepath and token to getappsecdesignfile method in my fileService.

现在让我们看一下我的fileService中的getappsecdesignfile方法.

Now Lets take a look at the getappsecdesignfile method in my fileService.

getappsecdesignfile ( token, tool5filepath ) : Observable<any>{

       console.log("In Service tool5filepath: ", tool5filepath);
       console.log("In Service token", token);
       console.log("In Service GET url: ", this.getappsecdesignfileurl);

       //Since the tool5filepath has / (slashes etc) I am encoding it below.

       let encodedtool5filepath = encodeURIComponent(tool5filepath);
       console.log('Encoded File Path: ', encodedtool5filepath);

       let req = new HttpRequest('GET', this.getappsecdesignfileurl,{params: new HttpParams().set('path', encodedtool5filepath)},{headers: new HttpHeaders().set('Accept', 'application/vnd.ms-excel').set('Authorization', token)});
       console.log(req);
       return this.http.request(req);

   }

这就是fileService方法的全部.让我们从浏览器查看此方法的console.logs,以确保设置了所有正确的值.

That's all there is to the fileService method. Lets look at the console.logs from this method from the browser to ensure all the correct values are being set.

现在让我们在进入服务器部分之前先看看请求本身.

Now Lets take a look at the request itself before we go to the server part.

就我而言,标题设置正确,参数设置正确.我看到的两个问题是Angular的拦截器可能设置了responseType:json并向我的请求中添加了一个参数op:s.

As far as I am concerned the headers are set correctly, params are set correctly. Two issues I see is that Angular's interceptors probably sets the responseType: json and adds a param op:s to my request.

节点/Express Server代码.

Node/Express Server code.

app.get('/getappsecdesignfile', function(req, res){
console.log("In get method app security design");
    accessTokenString = req.headers.authorization;
    console.log("Okta Auth Token:", accessTokenString);

    console.log("Tool5 File Path from received from Angular: ", req.query.path); //this is where the server console logs shows Tool5 File Path after decoding: ./undefined

    oktaJwtVerifier.verifyAccessToken(accessTokenString)
    .then(jwt => {
    // the token is valid
      console.log(jwt.claims);

      res.setHeader('Content-Disposition', 'attachment; filename= + Application_Security_Design.xlsx');
      res.setHeader('Content-Type', 'application/vnd.ms-excel');

      let tool5filepath = './' + decodeURIComponent(req.query.path);
      console.log("Tool5 File Path after decoding: ", tool5filepath);
      res.download(tool5filepath);

      }).catch(err => {
        // a validation failed, inspect the error
        res.json({success : false, message : 'Authorization error.'});
      });
    });

如果我使用Postman,则api可以正常运行.但是,在Angular与Node之间的通信中,发生了一些我不了解的事情.

If I use Postman the api works fine. However somewhere between Angular to Node communication something happens that I don't understand.

下面是服务器记录的内容. (大问题如何使它变得不确定)?

Below is what the server logs. (Big question how does this become undefined)?

Tool5 File Path from received from Angular:  undefined
Tool5 File Path after decoding:  ./undefined
Error: ENOENT: no such file or directory, stat '<dirpath>/undefined'

这是我在浏览器日志中看到的内容:

Here is what I see in the browser log:

zone.js:2933 GET http://localhost:3000/getappsecdesignfile 404 (Not Found)
toolinput.component.ts:137 Backend returned code 404, body was: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Error: ENOENT: no such file or directory, stat &#39;<dirpath>/undefined&#39;</pre>
</body>
</html>

然后浏览器下载损坏的xlsx文件,无法打开.

Then the browser downloads a xlsx file that is corrupt and cannot be opened.

我已检查文件驻留在目录中并准备下载.

I have checked the file resides in the directory and is ready to be downloaded.

感谢所有可以帮助我解决此问题的提示.

Thanks for any tips that can help me resolve this issue.

推荐答案

最后弄清楚了.

2项特定更改使这项工作得以实现.

2 specific changes made this work.

更改#1-设置responseType:'blob'并首先定义参数和标头,然后在http.get中使用它们. (http只是来自angular/common/http的HttpClient类型的对象,已被注入到服务类中.

Change # 1 - Setting responseType : 'blob' and defining the params and headers first and then using them in http.get. (http is nothing but an object of type HttpClient from angular/common/http that has been injected into the service class.

getappsecdesignfile ( token, tool5filepath ) : Observable<any>{

       console.log("In Service tool5filepath: ", tool5filepath);
       console.log("In Service token", token);
       console.log("In Service GET url: ", this.getappsecdesignfileurl);

       let encodedtool5filepath = encodeURIComponent(tool5filepath);
       console.log('Encoded File Path: ', encodedtool5filepath);

       let getfileparams = new HttpParams().set('filepath', encodedtool5filepath);
       let getfileheaders = new HttpHeaders().set('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet').set('Authorization', token);

       return this.http.get(this.getappsecdesignfileurl, {responseType: 'blob', params: getfileparams, headers: getfileheaders});
   }

更改#2-组件代码-FileSaver.由于某种原因,键入:'application/vnd.ms-excel'在FileSaver中不起作用.这里的res就是来自http.get调用的响应.

Change # 2 - Component code - FileSaver. For some reason type: 'application/vnd.ms-excel' did not work in FileSaver. Here the res is nothing but the response from the http.get call.

let blobtool5 = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
FileSaver.saveAs(blobtool5, 'Application_Security_Design.xlsx');

这篇关于如何使用带有Node/Express后端的Angular 5 HttpClient get方法下载Excel(xlsx)文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆