Node.js + JQuery Ajax. Загрузка файлов на сервер

в 12:24, , рубрики: javascript, jquery, node.js

Введение

В данные статье я хочу вам рассказать о моем способе загрузки файлов на сервер Node.js с помощью JQuery Ajax. Да, я понимаю что есть уже и другие решения, например JQuery File Upload, но все таки иногда хочется сделать что-то уже существующее, для того чтобы понять как это все устроено. Данное решение является учебным примером, все замечания по поводу кода или предложения по его улучшению оставляйте в комментариях.

Что будем использовать

  1. Bootstrap
  2. JQuery
  3. Модуль для Node.js Multiparty

Отправка файла с помощью Ajax

Конечно здесь наверное самый жуткий код. Все элементы на странице создаются вручную. За загрузку отвечает класс JSUploader вот один из его методов uploadFile:

this.uploadFile =  function(index) {
        //baseClass это this
        var file = baseClass.allFiles[index];

        //Создаем объек FormData
        var data = new FormData();
        //Добавлем туда файл
        data.append('uploadFile', file.file);

        //отсылаем с попощью Ajax
        $.ajax({
            url: '/',
            data: data,
            cache: false,
            contentType: false,
            processData: false,
            type: 'POST',
            success: function(response) {
                var message = file.element.find('td.message');
                if(response.status == 'ok') {
                    message.html(response.text);
                    file.element.find('button.uploadButton').remove();
                }
                else {
                    message.html(response.errors);
                }
            },
            xhr: function() {
                var xhr = $.ajaxSettings.xhr();

                if ( xhr.upload ) {
                    console.log('xhr upload');

                    xhr.upload.onprogress = function(e) {
                        file.progressDone = e.position || e.loaded;
                        file.progressTotal = e.totalSize || e.total;
                        //обновляем прогресс для файла
                        baseClass.updateFileProgress(index, file.progressDone, file.progressTotal, file.element);
                        //обновляем общий прогресс
                        baseClass.totalProgressUpdated();
                    };
                }

                return xhr;
            }
        });
    };

Обработка загрузки файлов

Для загрузки файлов на сервер нам понадобиться модуль multiparty, который можно установить с помощью команды в консоле:
npm install multiparty

Далее код который обрабатывает post и get запросы начальной страницы. Здесь мы отображаем форму загрузки и обрабатываем post запрос на загрузку файла.
При окончание загрузки мы сообщаем клиенту что все хорошо или если есть ошибки, то отправить их. Единственная проблема по моему мнению — это то, что в данном коде сервер не может сразу завершить загрузку и сообщить об ошибки, для этого приходиться ждать полной загрузки файла. Решение проблемы возможно если мы как-нибудь вызовем сигнал onclose у формы, но к сожалению пока решения я не нашел.

var express = require('express'),
    router = express.Router(),
    fs = require("fs"),
    multiparty = require('multiparty');

//здесь выводим форму для загрузки
router.get('/', function(req, res) {
  res.render('index', { title: 'Node.js File Uploads' });
});

//здесь происходит сама загрузка
router.post('/', function(req, res, next) {
    // создаем форму
    var form = new multiparty.Form();
    //здесь будет храниться путь с загружаемому файлу, его тип и размер
    var uploadFile = {uploadPath: '', type: '', size: 0};
    //максимальный размер файла
    var maxSize = 2 * 1024 * 1024; //2MB
    //поддерживаемые типы(в данном случае это картинки формата jpeg,jpg и png)
    var supportMimeTypes = ['image/jpg', 'image/jpeg', 'image/png'];
    //массив с ошибками произошедшими в ходе загрузки файла
    var errors = [];

     //если произошла ошибка
    form.on('error', function(err){
        if(fs.existsSync(uploadFile.path)) {
            //если загружаемый файл существует удаляем его
            fs.unlinkSync(uploadFile.path);
            console.log('error');
        }
    });

    form.on('close', function() {
        //если нет ошибок и все хорошо
        if(errors.length == 0) {
            //сообщаем что все хорошо
            res.send({status: 'ok', text: 'Success'});
        }
        else {
            if(fs.existsSync(uploadFile.path)) {
                //если загружаемый файл существует удаляем его
                fs.unlinkSync(uploadFile.path);
            }
            //сообщаем что все плохо и какие произошли ошибки
            res.send({status: 'bad', errors: errors});
        }
    });

    // при поступление файла
    form.on('part', function(part) {
        //читаем его размер в байтах
        uploadFile.size = part.byteCount;
        //читаем его тип
        uploadFile.type = part.headers['content-type'];
        //путь для сохранения файла
        uploadFile.path = './files/' + part.filename;

        //проверяем размер файла, он не должен быть больше максимального размера
        if(uploadFile.size > maxSize) {
            errors.push('File size is ' + uploadFile.size + '. Limit is' + (maxSize / 1024 / 1024) + 'MB.');
        }

        //проверяем является ли тип поддерживаемым
        if(supportMimeTypes.indexOf(uploadFile.type) == -1) {
            errors.push('Unsupported mimetype ' + uploadFile.type);
        }

        //если нет ошибок то создаем поток для записи файла
        if(errors.length == 0) {
            var out = fs.createWriteStream(uploadFile.path);
            part.pipe(out);
        }
        else {
            //пропускаем
            //вообще здесь нужно как-то остановить загрузку и перейти к onclose
            part.resume();
        }
    });

    // парсим форму
    form.parse(req);
});

Ссылки

Автор: xfakehopex

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js