如何使用带有Node / Express后端的Angular 5 HttpClient get方法下载Excel(xlsx)文件?

Aak*_*ash 2 node.js express filesaver.js angular

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

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

以下是我的Angular组件。

带有下载按钮的角度组件

这里是Angular中按钮的模板代码,单击后将调用saveFile()函数。

<a class="btn btn-primary" (click) = "saveFile()">Download</a>
Run Code Online (Sandbox Code Playgroud)

这是saveFile()函数。

   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);
                }
          });
    }
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

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

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);

   }
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明

现在让我们看一下请求本身,然后再转到服务器部分。

在此处输入图片说明

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

节点/ Express Server代码。

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.'});
      });
    });
Run Code Online (Sandbox Code Playgroud)

如果我使用Postman,则api效果很好。但是,在Angular与Node之间的通信中,发生了一些我不了解的事情。

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

Tool5 File Path from received from Angular:  undefined
Tool5 File Path after decoding:  ./undefined
Error: ENOENT: no such file or directory, stat '<dirpath>/undefined'
Run Code Online (Sandbox Code Playgroud)

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

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>
Run Code Online (Sandbox Code Playgroud)

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

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

在此处输入图片说明

感谢您提供任何可以帮助我解决此问题的提示。

Aak*_*ash 6

终于想通了。

进行了2项具体更改。

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

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});
   }
Run Code Online (Sandbox Code Playgroud)

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

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