2015-12-14 8 views
7

Sto tentando di gestire una richiesta POST sul mio server Node Express per gestire i caricamenti di moduli multipart, nel mio caso l'utente sta caricando le immagini.Caricamento di moduli multiparte su un altro server

Voglio collegare il caricamento a un altro server tramite la mia app Express che è attualmente impostata per utilizzare il parser del corpo, che inoltre non supporta i bode multipart e consiglia invece l'uso di alcune altre librerie.

Ho visto multiparty ma non sono sicuro di come utilizzarlo con la mia applicazione lato client.

Nel mio codice lato client Vi metto un oggetto formdata in questo modo:

function create(data, name) { 
    var formData = new FormData(); 
    formData.append('file', data, name); 
    return this.parentBase.one('photos').withHttpConfig({transformRequest: angular.identity}).customPOST(formData, undefined, undefined, {'Content-Type': undefined}); 
} 

Nota: Sto usando la libreria Restangular per AngularJS come documentato here

Quindi, da quello che ho capito cercando nei documenti multipartitico, devo gestire gli eventi di caricamento del modulo e intervenire ulteriormente una volta che il modulo ha terminato il caricamento.

Il fatto è che speravo di poter inviare il caricamento direttamente a un altro server. In precedenza la mia app lato client stava effettuando chiamate dirette a questo altro server, ma ora sto cercando di far passare tutto attraverso Express, è possibile, o devo usare qualcosa come multiparty?

La documentazione della richiesta fornisce un esempio dell'utilizzo di formData, ma non sono sicuro di come ciò potrebbe funzionare con gli esempi multiparty che ho visto. Ad esempio, una volta che l'upload è stato completato in Express usando la mutuaparty, devo quindi costruire un altro oggetto formData per poi effettuare un'ulteriore richiesta con o dovrei sottoporre a pipe ogni parte sull'altro server?

Sono confuso, per favore qualcuno può chiarire questo per me?

Grazie

EDIT

OK, ho dato un'occhiata a multer seguente @yarons commenti e questo sembra essere il genere di cosa che voglio di utilizzare, ho cercato di utilizzare questo con la mia configurazione del router espressa di cui qui di seguito:

routes.js

var express = require('express'), 
    router = express.Router(), 
    customers = require('./customers.controller.js'), 
    multer = require('multer'), 
    upload = multer(); 

router.post('/customers/:customerId/photos/', upload.single('file'), customers.createPhoto); 

controller.js

module.exports.createPhoto = function(req, res) { 
    console.log(req.file); 
    var options = prepareCustomersAPIHeaders(req); 
    options.formData = req.file; 
    request(options).pipe(res); 
}; 

Logging la proprietà req.file nel controller sopra vedo questo:

{ fieldname: 'file', 
    originalname: '4da2e703044932e33b8ceec711c35582.jpg', 
    encoding: '7bit', 
    mimetype: 'image/png', 
    buffer: <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 fa 00 
00 00 fa 08 06 00 00 00 88 ec 5a 3d 00 00 20 00 49 44 41 54 78 5e ac bd f9 8f e 
6 e9 7a ... >, 
    size: 105868 } 

Che è quello che metto attraverso dal codice lato client utilizzando:

var formData = new FormData(); 
     formData.append('file', data, name); 
     return this.parentBase.one('photos').withHttpConfig({transformRequest: angular.identity}).customPOST(formData, undefined, undefined, {'Content-Type': undefined}); 

È quello che ho provato ragionevole? Solo che non funziona, ricevo un errore dal server che sto cercando di pubblicare.In anticipo dove stavo facendo questa richiesta posta direttamente al server di tutto funzionava bene, quindi devo avere qualcosa che non va nel mio setup Express \ Multer

EDIT 2

Ok, quindi dopo più la caccia in giro sono arrivato attraverso this articolo utilizzando multipartitico che devo manager per ottenere lavorare nella mia messa a punto in questo modo:

var request = require('request'), 
    multiparty = require('multiparty'), 
    FormData = require('form-data'); 

module.exports.createPhoto = function(req, res) { 
    //console.log(req.file); 
    var options = prepareCustomersAPIHeaders(req), 
    form = new multiparty.Form(); 
    options.headers['Transfer-Encoding'] = 'chunked'; 

    form.on('part', function(part){ 
    if(part.filename) { 
     var form = new FormData(), r; 
     form.append(part.name, part, {filename: part.filename, contentType: part['content-type']}); 


     r = request(options, function(err, response, body){ 
     res.status(response.statusCode).send(body); 
     }); 
     r._form = form 
    } 
    }); 

    form.on('error', function(error){ 
    console.log(error); 
    }); 

    form.parse(req); 
}; 

questo è ora il caricamento dei file per me come previsto al mio altro assistente, mentre questa soluzione funziona, non mi piace la linea :

r._form = form 

sembra essere l'assegnazione di una variabile forma privata per l'oggetto di richiesta, oltre a non riesco a vedere tutto ciò che è documentato in questo modo su pagine multipartitiche

Qualcuno può offrire qualsiasi commento su questo possibile soluzione?

+0

Hai provato [multer] (https://github.com/expressjs/multer)? È un middleware che ti consente di accedere al file una volta caricato e non è necessario ascoltare gli eventi di caricamento – yarons

+0

Grazie a yarons, che sembra essere una libreria molto più semplice con cui lavorare, ho modificato il mio post con il codice Ho provato ma non riesco a farlo funzionare ancora. Sto costruendo un oggetto formData nel client per il post iniziale su Express, e speravo di usarlo così come è il valore del parametro formData nella chiamata di richiesta che voglio fare all'altro mio server. In questo momento sembra che io debba usare due oggetti formData, che non hanno un buon odore. – mindparse

+0

In [questa risposta] (http://stackoverflow.com/a/30375755/2759075), c'è un esempio di invio di un file da un server all'altro utilizzando [Needle] (https://github.com/tomas/ ago) (che non ho mai provato prima). Scusa, sto solo lanciando pacchetti di terze parti a te ... – yarons

risposta

0

Usiamo qualcosa di simile al seguente:

CLIENTE

//HTML 
    <input type="file" ng-file-select uploader="info.uploadPath" /> 


//DIRECTIVES 
    // It is attached to <input type="file" /> element 
    .directive('ngFileSelect', function() { 
    return { 
     link: function($scope, $element) { 
     $element.bind('change', function() { 
      $scope.$emit('file:add', this.files ? this.files : this); 
     }); 
     } 
    }; 
    }) 

//OTHER 
    var uploadPath = '/api/things/' + $stateParams.thingId + '/add_photo' 

    var uploadInfo = { 
       headers: { 
       'Authorization': authToken 
       }, 
       form: { 
       title: scope.info.name 
       } 
      } 


//SERVICE: 
    $rootScope.$on('file:add', function(event, items) { 
    this.addToQueue(items); 
    }.bind(this)); 
    ... 
    addToQueue: function(items) { 
    var length = this.queue.length; 
    angular.forEach(items.length ? items : [items], function(item) { 
     var isValid = !this.filters.length ? true : !!this.filters.filter(function(filter) { 
     return filter.apply(this, [item]); 
     }, this).length; 

     if (isValid) { 
     item = new Item({ 
      url: this.url, 
      alias: this.alias, 
      removeAfterUpload: this.removeAfterUpload, 
      uploader: this, 
      file: item 
     }); 

     this.queue.push(item); 
     } 
    }, this); 

    this.uploadAll(); 
    }, 
    getNotUploadedItems: function() { 
    return this.queue.filter(function(item) { 
     return !item.isUploaded; 
    }); 
    }, 

    /** 
    * Upload a item from the queue 
    * @param {Item|Number} value 
    */ 
    uploadItem: function(value, uploadInfo) { 
    if (this.isUploading) { 
     return; 
    } 

    var index = angular.isObject(value) ? this.getIndexOfItem(value) : value; 
    var item = this.queue[index]; 
    var transport = item.file._form ? '_iframeTransport' : '_xhrTransport'; 
    this.isUploading = true; 
    this[transport](item, uploadInfo); 
    }, 

    uploadAll: function(uploadInfo) { 
    var item = this.getNotUploadedItems()[0]; 
    this._uploadNext = !!item; 
    this._uploadNext && this.uploadItem(item, uploadInfo); 
    }, 

    _xhrTransport: function(item, uploadInfo) { 
    var xhr = new XMLHttpRequest(); 
    var form = new FormData(); 
    var that = this; 

    form.append(item.alias, item.file); 

    angular.forEach(uploadInfo.form, function(value, name) { 
     form.append(name, value); 
    }); 

    xhr.upload.addEventListener('progress', function(event) { 
     var progress = event.lengthComputable ? event.loaded * 100/event.total : 0; 
     that._scope.$emit('in:progress', item, Math.round(progress)); 
    }, false); 

    xhr.addEventListener('load', function() { 
     xhr.status === 200 && that._scope.$emit('in:success', xhr, item); 
     xhr.status !== 200 && that._scope.$emit('in:error', xhr, item); 
     that._scope.$emit('in:complete', xhr, item); 
    }, false); 

    xhr.addEventListener('error', function() { 
     that._scope.$emit('in:error', xhr, item); 
     that._scope.$emit('in:complete', xhr, item); 
    }, false); 

    xhr.addEventListener('abort', function() { 
     that._scope.$emit('in:complete', xhr, item); 
    }, false); 

    this._scope.$emit('beforeupload', item); 

    xhr.open('POST', item.url, true); 

    angular.forEach(uploadInfo.headers, function(value, name) { 
     xhr.setRequestHeader(name, value); 
    }); 

    xhr.send(form); 
    }, 

SERVER

//things.router 
app.route('/api/things/:thingId/add_photo') 
    .post(things.uploadPhoto); 

//things.controller 
exports.uploadPhoto = function(req, res) { 
    var formidable = require('formidable'); 

    var form = new formidable.IncomingForm(); 

    form.parse(req, function(err, fields, files) { 
    var data = files.qqfile; 
    //actual file is at data.path 
    fs.createReadStream(data.path).pipe(request.put(uploadUrl)); 
    } 
} 
Problemi correlati