title: Node + Angular : download a file with HTTP request
body: <p>I tried 400 combinations of syntaxes and headers, I can't figure out how to make a HTTP call from Angular to retrieve a file from my NodeJS server.</p>
  
  <p>Found on Stackoverflow and tried, to no avail :</p>
  
  <p><a href="https://stackoverflow.com/questions/51789871/download-file-from-http-post-request-angular-6/51843771">Download file from http post request - Angular 6</a></p>
  
  <p><a href="https://stackoverflow.com/questions/51682514/how-download-a-file-from-httpclient">How download a file from HttpClient</a></p>
  
  <p><a href="https://stackoverflow.com/questions/7288814/download-a-file-from-nodejs-server-using-express">Download a file from NodeJS Server using Express</a></p>
  
  <p><a href="https://stackoverflow.com/questions/35138424/how-do-i-download-a-file-with-angular2">How do I download a file with Angular2</a></p>
  
  <p>It can't be a simple <code>&lt;a download&gt;</code> tag, or a public <code>express.static()</code> folder, because access to the file is restricted and I need to pass a JWT token along (in Node, I have an Express authentication middleware that will reject the request if no token is provided in the headers or if it is invalid).</p>
  
  <p>The file is a GZIP : <code>./dumps/dump.gz</code> and weighs 812 Kb.</p>
  
  <p>I do manage to download the file, but whatever I try, it weighs 1.4 MB or 94 bytes (wrong size) and can't be opened (7zip <code>can't open file downloads/dump.gz as archive</code>).</p>
  
  <p>What I have tried <strong>Angular-side</strong> (multiple attempts) :</p>
  
  <pre><code>import { saveAs } from 'file-saver';
  
  let headers = new Headers({
      "Authorization": "Bearer " + user.jwt, // I need this in the headers
  
      "Content-Type" : "application/octet-stream", // Tried with and without, "application/gzip", "application/json", no difference
  
      "responseType": "blob" as "json", // Tried with and without, "text", "json", no difference
  
      "Access-Control-Expose-Headers" : "Content-Disposition" // Tried with and without, no difference
  })
  
  this.http
      .get("/download/dump", { headers })
      .toPromise()
      .then(res =&gt; {
  
          const blob = new Blob([res["_body"]] , { type: "application/octet-stream;"} );  // Error : body is not a blob or an array buffer
          // const blob = new Blob([res["_body"]]); // Same result
          // const blob = new Blob([res.blob()]); // Error : body is not a blob or an array buffer
  
          saveAs(blob, "dump.gz"); // Saves a big corrupted file
  
          // window.URL.createObjectURL(new Blob(blob, {type: 'blob'})); Saves a 94 byte corrupted file. Tried {type: 'gzip'}, same thing
      })
      .catch(err =&gt; console.error("download error = ", err))
  </code></pre>
  
  <p><strike>What I have tried <strong>Node-side</strong> (multiple attempts) :</strike></p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Node has been innocented as I could retrieve the file directly from Chrome after disabling authentication. So, the back-end works and the issue is in Angular.</p>
  
  <pre><code>app.get( "/download/dump", authenticate, (req:Request, res:Response) =&gt; {
      const file = path.resolve(__dirname, `./dumps/dump.gz`);
  
      res
          .set({ // Tried with and without headers, doesn't seem to do anything
              "Content-Disposition" : "attachment",  // Tried with and without
              "filename" : "dump.gz", // Tried with and without
              "filename*" : "dump.gz",  // Tried with and without
              "Content-Encoding" : "gzip",  // Tried with and without
              "Content-Type" : "application/gzip"  // Tried with and without, "application/text", "application/json", no difference 
          })
          .sendFile(file); // getting a big corrupted file
          // .download(file); // Same result (big corrupted file)
  })
  </code></pre>