2015-07-24 12 views
12

Ho creato un'app Web utilizzando AngularJs in cui l'utente può caricare file .txt su un server utilizzando ng-file-upload.Impossibile utilizzare l'esempio wiki http-server

ora volevo un semplice server Node.js per testare la parte di upload e vedere come il progresso bar e messaggi di errore nella pagina di comportarsi, ma che hanno una molto povera conoscenza su come Node.js e l'intera opera di backend cosa , Ho provato ad utilizzare il server Node.js fornito dal ng-file-upload molto wiki.

ho provato a fare alcune modifiche che mi hanno portato a questa app.js di file:

var http = require('http') 
    , util = require('util') 
    , multiparty = require('multiparty') 
    , PORT = process.env.PORT || 27372 

var server = http.createServer(function(req, res) { 
    if (req.url === '/') { 
    res.writeHead(200, {'content-type': 'text/html'}); 
    res.end(
     '<form action="/upload" enctype="multipart/form-data" method="post">'+ 
     '<input type="text" name="title"><br>'+ 
     '<input type="file" name="upload" multiple="multiple"><br>'+ 
     '<input type="submit" value="Upload">'+ 
     '</form>' 
    ); 
    } else if (req.url === '/upload') { 
    var form = new multiparty.Form(); 

    form.parse(req, function(err, fields, files) { 
     if (err) { 
     res.writeHead(400, {'content-type': 'text/plain'}); 
     res.end("invalid request: " + err.message); 
     return; 
     } 
     res.writeHead(200, {'content-type': 'text/plain'}); 
     res.write('received fields:\n\n '+util.inspect(fields)); 
     res.write('\n\n'); 
     res.end('received files:\n\n '+util.inspect(files)); 
    }); 
    } else { 
    res.writeHead(404, {'content-type': 'text/plain'}); 
    res.end('404'); 
    } 
}); 
server.listen(PORT, function() { 
    console.info('listening on http://127.0.0.1:'+PORT+'/'); 
}); 

ei UserController.js è semplice come questo

UserController = function() {}; 

UserController.prototype.uploadFile = function(req, res) { 
    // We are able to access req.files.file thanks to 
    // the multiparty middleware 
    var file = req.files.file; 
    console.log(file.name); 
    console.log(file.type); 
} 

module.exports = new UserController(); 

All'interno di una direttiva del controller nella mia app AngularJs Uso il servizio di caricamento ng-file-upload in questo modo

var upload = Upload.upload({ 
    url: 'http://127.0.0.1:27372/upload', 
    method: 'POST', 
    fields: newFields, 
    file: newFile 
    }).progress(function (evt) { 
     $scope.progressPercentage = parseInt(100.0 * evt.loaded/evt.total); 
    }).success(function (data, status, headers, config) { 
     console.log("OK"); 
    }).error(function(data, status, headers, config) { 
     console.log("KO"); 
}); 

Infine, avviare il server in questo modo:

node app.js 

e tutto guarda bene:

listening on http://127.0.0.1:27372 

Con tutto ciò che viene detto, quando lancio il web AngularJs -app e prova a caricare un file ottengo il seguente errore

OPTIONS http://127.0.0.1:27372/upload 400 (Bad Request)         angular.js:10514 
XMLHttpRequest cannot load http://127.0.0.1:27372/upload. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 400.     (index):1 

Dopo un po 'googling ho trovato molti GIST utilizzati per consentire le richieste CORS come this one, ma la mia conoscenza Node.js è così povero che non so nemmeno dove devo mettere quelle righe di codice.

Inoltre, ho cercato di ottenere un console.log(err) entro la parte app.jsform.parse stessa e preso a questa stampate sul terminale:

DEBUG SERVER: err = 
{ [Error: missing content-type header] status: 415, statusCode: 415 } 

What am I missing and what can I do to get this simple Node.js server working?


EDIT 29/07/2015

Ho scelto di seguire la prima opzione suggerita da @ Can Guney Aksakalli, perché è l'unico che posso fare, ma anche se ora il codice è simile al seguente:

var server = http.createServer(function(req, res) { 
    res.setHeader('Access-Control-Allow-Origin', '*'); 
    res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); 
    if (req.url === '/') { 
    res.writeHead(200, {'Content-type': 'text/html'}); 
// and the code stays the same 

Questa soluzione non funziona; Continuo a ricevere lo stesso messaggio di errore sia nella console di Chrome che nel terminale da cui ho chiamato node app.js, come ho scritto nell'ultima parte della mia domanda iniziale.

+0

Ho aggiunto codice di esempio per risolvere il problema CORS. –

risposta

7

Si stanno servendo i file html su http://localhost:9000 e l'applicazione NodeJS su http://localhost:27372; quindi hai un problema con CORS.(Questo problema non è correlato ad angularjs). È necessario abilitare CORS per NodeJS o servire tutte le applicazioni nello stesso dominio.

Possibili soluzioni:

1- Abilitazione CORS in server di NodeJS

È possibile attivare CORS nel lato server specificando origini ammessi in intestazione di risposta. Queste linee abiliterebbero richieste alla tua applicazione da tutti i domini. (Aggiungere questo all'inizio della definizione di funzione.)

var server = http.createServer(function(req, res) { 
    res.setHeader('Access-Control-Allow-Origin', '*'); 
    res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); 

    // the rest of the method ... 

} 

CORS Abilitazione per tutti di dominio non è sempre una buona decisione, si prega di controllare anche this.

2- Servire i file HTML dall'applicazione NodeJS

Qui con le seguenti aggiunte tu possa servire i file HTML dal server NodeJS. (Non è necessario utilizzare più l'altro server.)

var serveStatic = require('serve-static'); 
var finalhandler = require('finalhandler'); 

//... 

var serve = serveStatic('./path/to/your/static/folder'); 

var server = http.createServer(function(req, res) { 

    //... 

    var done = finalhandler(req, res); 
    serve(req, res, done); 
}); 

Io consiglio anche di utilizzare ExpressJS per funzionalità server più ricche invece di vaniglia Node.JS server HTTP.

3- Fornire una connessione proxy dal server file html per nodejs app

Non so che cosa si sta utilizzando come server per i file HTML statico, ma è possibile avere un proxy tra il server statico al server delle applicazioni NodeJS.


EDIT 1

Ecco un'implementazione di base per l'opzione 2- Serving your html files from NodeJS application.

In questo esempio ho usato ExpressJS. I file statici lato client vengono pubblicati nella cartella pubblica, per la richiesta di post all'url /api/upload caricare il file. Ecco il codice del server app.js:

var express = require('express'), 
    path = require('path'), 
    multiparty = require('connect-multiparty'), 
    multipartyMiddleware = multiparty(), 
    PORT = process.env.PORT || 27372; 

var app = express(); 

app.use(express.static(path.join(__dirname, 'public'))); 

app.post('/api/upload', multipartyMiddleware, function(req, res) { 
    var file = req.files.file; 
    console.log(file.name); 
    console.log(file.type); 
    console.log(file.path); 
}); 

var server = app.listen(PORT, function() { 
    var host = server.address().address; 
    var port = server.address().port; 
    console.log('the App listening at http://%s:%s', host, port); 
}); 

Ora cartella public è servita a URL principale. Ecco il file client public/index.html:

<!DOCTYPE html> 
<html> 
<head lang="en"> 
    <meta charset="UTF-8"> 
    <title>Upload example</title> 
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"> 
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> 
</head> 
<body> 
    <div class="container"> 
    <div> 
     <h1>Upload example</h1> 
     <hr /> 
     <div ng-app="fileUpload" ng-controller="MyCtrl"> 
     <button type="button" class="btn btn-default" ngf-select ng-model="file">Upload using model $watch</button> 
     </div> 
    </div> 
    </div> 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script> 
    <script src="http://rawgit.com/danialfarid/ng-file-upload/master/dist/ng-file-upload.min.js"></script> 
    <script> 
    var app = angular.module('fileUpload', ['ngFileUpload']); 
    app.controller('MyCtrl', ['$scope', 'Upload', function($scope, Upload) { 
     $scope.$watch('file', function() { 
     var file = $scope.file; 
     if (!file) { 
      return; 
     } 
     Upload.upload({ 
      url: 'api/upload', 
      file: file 
     }).progress(function(evt) { 
      var progressPercentage = parseInt(100.0 * evt.loaded/evt.total); 
      console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name); 
     }).success(function(data, status, headers, config) { 
      console.log('file ' + config.file.name + 'uploaded. Response: ' + data); 
     }).error(function(data, status, headers, config) { 
      console.log('error status: ' + status); 
     }) 
     });; 
    }]); 
    </script> 
</body> 
</html> 

Ora è possibile eseguire node app e provarlo sul localhost:27372 con il proprio browser.

(Qui è la versione Gist: https://gist.github.com/aksakalli/1a56072f066d65248885)


EDIT 2

Ecco un'implementazione di base per l'opzione 1- Enabling CORS in NodeJS server.Sto usando cors pacchetto per gestire la configurazione di testa, ora app.js codice sarebbe simile a questo:

+0

Ciao, grazie per aver risposto; Ho modificato la mia risposta e vorrei che la verificassi. – Gargaroz

+1

@Gargaroz Ho scritto per te una app di esempio. L'ho provato, dovrebbe funzionare. –

+0

grazie per lo sforzo in questa risposta, domani controllerò se la tua soluzione funziona – Gargaroz

3

Per il primo errore:

OPTIONS http://127.0.0.1:27372/upload 400 (Bad Request)         angular.js:10514 

La Carica di servizio ng-di caricamento file che si sta utilizzando rimuove l'intestazione Content-Type, come visto here, prima della richiesta. Ma sembra che il metodo parse da multiparty lo richieda. Se stai lavorando dall'esempio fornito dal wiki, ti consiglierei di usare anche express e multiparty come middleware, come indicato in quell'esempio.

vostri app.js sarebbe simile a quello:

var express = require('express'), 
// Requires multiparty 
multiparty = require('connect-multiparty'), 
multipartyMiddleware = multiparty(); 

var app = express(); 

app.all('*', function(req, res, next) { 
    res.header("Access-Control-Allow-Origin", "*"); 
    res.header("Access-Control-Allow-Headers", "X-Requested-With"); 
    next(); 
}); 

// Example endpoint 
app.post('/upload', multipartyMiddleware, function(req, res) { 
    // We are able to access req.files.file thanks to 
    // the multiparty middleware 
    var file = req.files.file; 
    console.log(file.type); 
    console.log(file.name); 
}); 

app.listen(27372); 

Per il secondo errore: E 'un problema CORS come accennato. La app.js proposta dovrebbe consentire CORS a causa delle seguenti righe:

app.all('*', function(req, res, next) { 
    res.header("Access-Control-Allow-Origin", "*"); 
    res.header("Access-Control-Allow-Headers", "X-Requested-With"); 
    next(); 
}); 
+0

Per la tua prima risposta: amico ho affermato nella mia domanda che non conosco molto Nodo, quindi non so cosa fai significa dire che devo "usare express e multiparty come middleware"; per la seconda risposta, ho riavviato il server Node ogni volta che ho cambiato qualcosa all'interno del codice – Gargaroz

+1

Il [collegamento wiki] (https://github.com/danialfarid/ng-file-upload/wiki/Node-example) che hai fornito , afferma nella prima frase, che in questo esempio viene utilizzato express e connect-multiparty (ovvero un pacchetto middleware di connessione). Fornisce inoltre collegamenti a entrambi, [la pagina Web esplicita] (http://expressjs.com/) e [connect-multiparty] (https://github.com/andrewrk/connect-multiparty). Presumo che tu abbia letto quei link. Inoltre non includi mai UserController.js ovunque nel tuo codice. –

+0

In realtà ho pensato che il codice su quella wiki sarebbe stato più pronto per l'uso, in quanto avevo solo bisogno di un semplice server per testare il mio front-end. Inoltre, @Can Guney sembra non includere UserController.js nelle soluzioni che ha fornito, un po 'di confusione per me – Gargaroz