NodeJS 文件的上传与下载

网上虽然有各种实例,可在实际使用中,存在各种问题,同时对错误并没有完善的处理。所以经过反复的调试,成功后,在此做个知识总结。

需求

  • 开发语言: Typescript
  • 在 Electron Render 线程中调用
  • 用 Promise 方式实现
  • 下载用 pipe 方式,更好的支持大文件
  • 上传支持附加请求参数
  • 上传支持附加头部信息
  • 完善的错误捕获逻辑,抛出统一的错误类型,方便捕获处理

依赖库

# For download
yarn add request

# For upload
yarn add form-data

逻辑代码

  • transfer.ts
import FormData from 'form-data/lib/form_data';
import request from 'request';
import * as fs from 'fs';
import { IncomingMessage } from 'http';

export function TransferError(message: string = '', code: number = -1) {
  this.name = 'TransferError';
  this.message = message;
  this.code = code;
}
TransferError.prototype = Error.prototype;

// Transfer file between local and remote.
class Transfer {
  debug: Function | null = null; // Example: transfer.debug = console.log

  // Upload file to remote.
  upload(
    url: string,
    filePath: string,
    params: any = {},
    addHeaders: any = {}
  ) {
    return new Promise((resolve, reject) => {
      const stream = fs.createReadStream(filePath);
      stream.on('error', (e: any) => reject(new TransferError(e)));

      const form = new FormData();
      form.append('file', stream);
      for (const k in params) {
        form.append(k, params[k]);
      }

      const u = new URL(url);
      const data = {
        protocol: u.protocol,
        host: u.hostname,
        port: u.port,
        path: u.pathname,
        headers: {},
      };
      for (const k in addHeaders) {
        data.headers[k] = addHeaders[k];
      }

      if (this.debug) {
        this.debug(`[transfer] upload - data: ${JSON.stringify(data)}`);
      }

      form
        .submit(data, (e: any, resp: IncomingMessage) => {
          if (e || resp.statusCode !== 200) {
            if (resp) {
              reject(new TransferError(resp.statusMessage, resp.statusCode));
            } else {
              reject(new TransferError(e));
            }
          } else {
            resolve(resp.read());
          }
        })
        .on('error', (e: any) => {
          reject(new TransferError(e));
        });
    });
  }

  // Download file from remote.
  download(url: string, destPath: string) {
    return new Promise((resolve, reject) => {
      const r = request(url);
      r.on('response', (resp: IncomingMessage) => {
        if (resp.statusCode === 200) {
          const writer = fs.createWriteStream(destPath);
          r.pipe(writer)
            .on('error', (e: any) => reject(new TransferError(e)))
            .on('finish', resolve);
        } else {
          reject(new TransferError(resp.statusMessage, resp.statusCode));
        }
      }).on('error', (e: any) => reject(new TransferError(e)));
    });
  }
}

export const transfer = new Transfer();

测试代码

  • transfer_test.ts
import { transfer, TransferError } from './transfer';

async function upload() {
  const url = 'http://192.168.10.11:8081/upload';
  const filePath = '/Users/mac/Desktop/upload.jpg';
  const openid = 'cd2b61ce043f6eed3f9d86aa6e670dba91a436ac';
  const token =
    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyIjp7ImlkIjoxLCJvcGVuaWQiOiJlZjE2NDU3YS0wNDgxLTRlYzUtOTQzMS0yZDhlYTA3MDdkODkifSwiZXhwIjoxNTc2NTAwNTA4LCJpc3MiOiJub3RlZG93bi5hdXRoIn0.86IwjCon8F3s5Pngn6gK5uuPrxEUmgFvzpkm_Jfhrzc';
  const addHeaders = {
    Authorization: `token ${token}`,
  };

  transfer.debug = console.log;
  try {
    const resp = await transfer.upload(url, filePath, { openid }, addHeaders);
    console.log('upload success', resp);
  } catch (e) {
    if (e instanceof TransferError) {
      console.log(e);
    } else {
      console.error(e);
    }
  }
}

async function download() {
  const url =
    'http://192.168.10.11:8081/static/86500d81f4a0921e27b4fbd89ce1eb1cc164109f.jpg';
  const filePath = '/Users/mac/Desktop/download.jpg';

  try {
    const resp = await transfer.download(url, filePath);
    console.log('download success', resp);
  } catch (e) {
    if (e instanceof TransferError) {
      console.log(e);
    } else {
      console.error(e);
    }
  }
}

export default function test() {
  upload();
  download();
}

你可能感兴趣的:(NodeJS 文件的上传与下载)