2015-12-04 4 views
2

Мне удалось загрузить файл на сервер Node с помощью модуля multer, выбрав файл, используя диалоговое окно ввода файла, а затем, отправив форму, но теперь мне понадобится вместо отправив форму, создать объект FormData и отправить файл с помощью XMLHttpRequest, но он не работает, файл всегда undefined на стороне сервера (маршрутизатор).Загрузка файла с помощью FormData и multer

Функция, которая делает запрос AJAX является:

function uploadFile(fileToUpload, url) { 

    var form_data = new FormData(); 

    form_data.append('track', fileToUpload, fileToUpload.name); 

    // This function simply creates an XMLHttpRequest object 
    // Opens the connection and sends form_data 
    doJSONRequest("POST", "/tracks/upload", null, form_data, function(d) { 
    console.log(d); 
    }) 

} 

Обратите внимание, что fileToUpload определена и url является правильным, так как правильный метод маршрутизатор называется. fileToUpload - это объект File, полученный путем удаления файла из файловой системы в dropzone, а затем путем доступа к свойству dataTransfer события drop.

doJSONRequest - это функция, которая создает объект XMLHttpRequest и отправляет файл и т. Д. (Как поясняется в комментариях).

function doJSONRequest(method, url, headers, data, callback){ 

    //all the arguments are mandatory 
    if(arguments.length != 5) { 
    throw new Error('Illegal argument count'); 
    } 

    doRequestChecks(method, true, data); 

    //create an ajax request 
    var r = new XMLHttpRequest(); 

    //open a connection to the server using method on the url API 
    r.open(method, url, true); 

    //set the headers 
    doRequestSetHeaders(r, method, headers); 

    //wait for the response from the server 
    r.onreadystatechange = function() { 
    //correctly handle the errors based on the HTTP status returned by the called API 
    if (r.readyState != 4 || (r.status != 200 && r.status != 201 && r.status != 204)){ 
     return; 
    } else { 
     if(isJSON(r.responseText)) 
     callback(JSON.parse(r.responseText)); 
     else if (callback !== null) 
     callback(); 
    } 
    }; 

    //set the data 
    var dataToSend = null; 
    if (!("undefined" == typeof data) 
    && !(data === null)) 
    dataToSend = JSON.stringify(data); 

    //console.log(dataToSend) 

    //send the request to the server 
    r.send(dataToSend); 
} 

И вот doRequestSetHeaders:

function doRequestSetHeaders(r, method, headers){ 

    //set the default JSON header according to the method parameter 
    r.setRequestHeader("Accept", "application/json"); 

    if(method === "POST" || method === "PUT"){ 
    r.setRequestHeader("Content-Type", "application/json"); 
    } 

    //set the additional headers 
    if (!("undefined" == typeof headers) 
    && !(headers === null)){ 

    for(header in headers){ 
     //console.log("Set: " + header + ': '+ headers[header]); 
     r.setRequestHeader(header, headers[header]); 
    } 

    } 
} 

и мой маршрутизатор для загрузки файлов является следующим

// Code to manage upload of tracks 
var multer = require('multer'); 
var uploadFolder = path.resolve(__dirname, "../../public/tracks_folder"); 

function validTrackFormat(trackMimeType) { 
    // we could possibly accept other mimetypes... 
    var mimetypes = ["audio/mp3"]; 
    return mimetypes.indexOf(trackMimeType) > -1; 
} 

function trackFileFilter(req, file, cb) { 
    cb(null, validTrackFormat(file.mimetype)); 
} 

var trackStorage = multer.diskStorage({ 
    // used to determine within which folder the uploaded files should be stored. 
    destination: function(req, file, callback) { 

    callback(null, uploadFolder); 
    }, 

    filename: function(req, file, callback) { 
    // req.body.name should contain the name of track 
    callback(null, file.originalname); 
    } 
}); 

var upload = multer({ 
    storage: trackStorage, 
    fileFilter: trackFileFilter 
}); 


router.post('/upload', upload.single("track"), function(req, res) { 
    console.log("Uploaded file: ", req.file); // Now it gives me undefined using Ajax! 
    res.redirect("/"); // or /#trackuploader 
}); 

Я думаю, что multer не понимая, что fileToUpload файл с именем track (не так ли?), То есть промежуточное ПО upload.single("track") не работает/разбирается правильно или ничего, или, может быть, оно подразумевает, что не работает с FormData, в этом случае это будет беспорядок. Какими альтернативами можно было бы воспользоваться, используя multer?

Как загрузить файл с помощью AJAX и multer?

Не стесняйтесь спрашивать, нужна ли вам дополнительная информация.

+0

Привет, попробуйте это .http: // jasonshultz.com/blog/file-upload-with-angularjs-node-and-express –

ответ

6

multer использует multipart/form-data запросы на контент для загрузки файлов. Удаление этого бита из вашей doRequestSetHeaders функции должны решить вашу проблему:

if(method === "POST" || method === "PUT"){ 
    r.setRequestHeader("Content-Type", "application/json"); 
} 

Вам не нужно указать content-type с момента FormData объектов уже используется правильный тип кодирования. Из docs:

передаваемые данные в том же формате, что форма Передать() метода будет использовать для передачи данных, если тип кодирования формы были установлены для MULTIPART/форм-данных.

Вот рабочий пример. Это предполагает, что есть Dropzone с идентификатором drop-zone и кнопка загрузки с идентификатором upload-button:

var dropArea = document.getElementById("drop-zone"); 
var uploadBtn = document.getElementById("upload-button"); 
var files  = []; 

uploadBtn.disabled = true; 
uploadBtn.addEventListener("click", onUploadClick, false); 

dropArea.addEventListener("dragenter", prevent, false); 
dropArea.addEventListener("dragover", prevent, false); 
dropArea.addEventListener("drop", onFilesDropped, false); 

//---------------------------------------------------- 
function prevent(e){ 

    e.stopPropagation(); 
    e.preventDefault(); 
} 

//---------------------------------------------------- 
function onFilesDropped(e){ 

    prevent(e); 

    files = e.dataTransfer.files; 

    if (files.length){ 
     uploadBtn.disabled = false; 
    } 
} 

//---------------------------------------------------- 
function onUploadClick(e){ 

    if (files.length){ 
     sendFile(files[0]); 
    } 
} 

//---------------------------------------------------- 
function sendFile(file){ 

    var formData = new FormData(); 
    var xhr  = new XMLHttpRequest(); 

    formData.append("track", file, file.name); 

    xhr.open("POST", "http://localhost:3000/tracks/upload", true); 

    xhr.onreadystatechange = function() { 
     if (xhr.readyState === 4) { 
      if (xhr.status === 200) { 
       console.log(xhr.responseText); 
      } else { 
       console.error(xhr.statusText); 
      } 
     } 
    }; 

    xhr.send(formData); 
} 

на стороне сервера код простой экспресс-приложение с точным кодом маршрутизатора вы указали.

+0

Я сказал, что моя форма многочастна, т. е. у меня есть другие типы полей в моей форме ..? – nbro

+0

Я не уверен, что я понимаю ваш вопрос? «content-type» для этого запроса устанавливается как «multipart/form-data; border = ---- WebKitFormBoundary ...», как и ожидалось. В противном случае multer даже не работал бы с ним в первую очередь. Вы можете добавить дополнительные поля, используя formData.append, и прочитать их из req.body. – cviejo

+0

Я еще не пробовал ваш код, но он действительно кажется похожим на мои, поэтому я не понимаю, почему ваш должен работать ... не могли бы вы объяснить, почему это должно работать? – nbro