How to download a file with Node.js (without using third-party libraries)?

后端 未结 28 1200
逝去的感伤
逝去的感伤 2020-11-22 03:37

How do I download a file with Node.js without using third-party libraries?

I don\'t need anything special. I only want to download a file from a giv

28条回答
  •  囚心锁ツ
    2020-11-22 04:16

    Writing my own solution since the existing didn't fit my requirements.

    What this covers:

    • HTTPS download (switch package to http for HTTP downloads)
    • Promise based function
    • Handle forwarded path (status 302)
    • Browser header - required on a few CDNs
    • Filename from URL (as well as hardcoded)
    • Error handling

    It's typed, it's safer. Feel free to drop the types if you're working with plain JS (no Flow, no TS) or convert to a .d.ts file

    index.js

    import httpsDownload from httpsDownload;
    httpsDownload('https://example.com/file.zip', './');
    

    httpsDownload.[js|ts]

    import https from "https";
    import fs from "fs";
    import path from "path";
    
    function download(
      url: string,
      folder?: string,
      filename?: string
    ): Promise {
      return new Promise((resolve, reject) => {
        const req = https
          .request(url, { headers: { "User-Agent": "javascript" } }, (response) => {
            if (response.statusCode === 302 && response.headers.location != null) {
              download(
                buildNextUrl(url, response.headers.location),
                folder,
                filename
              )
                .then(resolve)
                .catch(reject);
              return;
            }
    
            const file = fs.createWriteStream(
              buildDestinationPath(url, folder, filename)
            );
            response.pipe(file);
            file.on("finish", () => {
              file.close();
              resolve();
            });
          })
          .on("error", reject);
        req.end();
      });
    }
    
    function buildNextUrl(current: string, next: string) {
      const isNextUrlAbsolute = RegExp("^(?:[a-z]+:)?//").test(next);
      if (isNextUrlAbsolute) {
        return next;
      } else {
        const currentURL = new URL(current);
        const fullHost = `${currentURL.protocol}//${currentURL.hostname}${
          currentURL.port ? ":" + currentURL.port : ""
        }`;
        return `${fullHost}${next}`;
      }
    }
    
    function buildDestinationPath(url: string, folder?: string, filename?: string) {
      return path.join(folder ?? "./", filename ?? generateFilenameFromPath(url));
    }
    
    function generateFilenameFromPath(url: string): string {
      const urlParts = url.split("/");
      return urlParts[urlParts.length - 1] ?? "";
    }
    
    export default download;
    

提交回复
热议问题