КЛИЕНТ:

  1. Получить файл из input[type=file]:
const { files } = e.target;
file = files[0];

2. Затем нам нужно разрезать файл на части (я буду разрезать их на части по 100кБ):

const slice = file.slice(0, 100000);

3. Теперь мы можем начать отправлять эти слайсы, но перед этим мы должны прочитать файл как Array Buffer:

const fileReader = new FileReader();
fileReader.onload = () => {
  const int8Array = new Int8Array(fileReader.result);

  const data = [];

  each(int8Array, (item) => {
    data.push(item);
  });
  // function right below is for emit websocket message to server it takes 2 parameters: 1 - type of message, 2 - data to send
  executeWebsocketRequest(SLICE_UPLOAD, {
    name: file.name,
    type: file.type,
    size: file.size,
    data,
  });
};

fileReader.readAsArrayBuffer(slice);

СЕРВЕР:

4. Здесь мы обработаем получение фрагментов изображения от клиента и проверим, получили ли мы все фрагменты, после чего загрузка файла закончилась:

const files = {},
  struct = {
    name: null,
    type: null,
    size: 0,
    data: [],
    slice: 0,
  };
export const uploadFile = (ws, data) => {
  const sliceData = data.data;

  if (!files[sliceData.name]) {
    files[sliceData.name] = Object.assign({}, struct, sliceData);
    files[sliceData.name].data = [];
  }

  //convert the Object to Int8Array and then to Buffer
  sliceData.data = new Buffer(new Int8Array(sliceData.data));

  //save the data
  files[sliceData.name].data.push(sliceData.data);
  files[sliceData.name].slice++;

  if (files[sliceData.name].slice * 100000 >= files[sliceData.name].size) {
    // file upload ended and we can send it to AWS S3 bucket
    sendToOpenedSocket(ws, { type: IMAGE_UPLOAD_ENDED });
    
    // Concat all the image slices to one Buffer
    const fileBuffer = Buffer.concat(files[sliceData.name].data);
    const type = sliceData.type.split('/');

    if (type[0] !== IMAGE) {
      // TODO write checking functionality for no image files and send error to client
      return;
    }

    uploadFileToAWS(fileBuffer, sliceData.name, type)
      .then((data) => {
        // add aws file link to db document field image
        const { collectionName, _id } = sliceData;
        documentUpdate(ws, { data: { collectionName: collectionName, _id, fields: { image: data.Location }}});

        delete files[data.name];
      })
      .catch((err) => {
        console.log('aws error', err)
      })
  } else {
    sendToOpenedSocket(ws, { type: NEXT_IMAGE_SLICE_UPLOAD, currentSlice: files[sliceData.name].slice })
  }
};

5. Как видите, мы также написали функционал для загрузки изображений в корзину AWS S3. (https://medium.com/quant-five/node-js-with-amazon-sdk-for-s3-uploads-d20dd5c9ca4b)

// configure the keys for accessing AWS
AWS.config.update({
  accessKeyId: AWS_ACCESS_KEY_ID,
  secretAccessKey: AWS_SECRET_ACCESS_KEY
});

// configure AWS to work with promises
AWS.config.setPromisesDependency(bluebird);

// create S3 instance
const s3 = new AWS.S3();

export const uploadFileToAWS = (buffer, name, type) => {
  const params = {
    ACL: 'public-read',
    Body: buffer,
    Bucket: S3_BUCKET,
    ContentType: type[0],
    Key: name
  };

  return s3.upload(params).promise();
};