...

понедельник, 14 июля 2014 г.

[Из песочницы] Node.js + JQuery Ajax. Загрузка файлов на сервер

Введение




В данные статье я хочу вам рассказать о моем способе загрузки файлов на сервер 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);
});


Ссылки




This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий