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