Невозможно использовать пример вики-сервера http-server

Я сделал веб-приложение, используя AngularJs, где пользователь может загружать файлы .txt на сервер, используя ng-file-upload.

Теперь мне нужен простой сервер Node.js, чтобы проверить загружаемую часть и посмотреть, как ведут себя индикаторы выполнения и сообщения об ошибках на странице, но имеющие очень плохие знания о том, как Node.js и вся бэкэндовая вещь Я попытался использовать сервер Node.js, предоставленный ng-file-upload очень wiki.

Я попытался внести некоторые изменения, которые привели меня к этому файлу app.js:

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+'/');
});

и UserController.js прост, как этот

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();

Внутри контроллера директивы в моем приложении AngularJs я использую ng-file-upload службу загрузки таким образом

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");
});

Наконец, я запустил сервер следующим образом:

node app.js

и все выглядит нормально:

listening on http://127.0.0.1:27372

При всем том, когда я запускаю веб-приложение AngularJs и пытаюсь загрузить файл, я получаю следующую ошибку:

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

После некоторых поисковых запросов я обнаружил, что многие gists использовали для запросов CORS, таких как этот, но мои знания Node.js настолько бедны, что я даже не знаю где я должен поместить эти строки кода.

Кроме того, я попытался получить console.log(err) внутри самой части app.js form.parse и получил это сообщение на терминале:

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

Что мне не хватает и что я могу сделать, чтобы получить этот простой сервер Node.js работать?


EDIT 29/07/2015

Я решил следовать первому варианту, предложенному @Can Guney Aksakalli, потому что это единственный, который я могу сделать, но даже если теперь код выглядит следующим образом:

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

Это решение не работает; Я продолжаю получать то же сообщение об ошибке как на консоли Chrome, так и на терминале, с которого я звонил node app.js, как я писал в последней части моего первоначального вопроса.

Ответ 1

Вы обслуживаете html файлы в http://localhost:9000 и приложении NodeJS на http://localhost:27372; поэтому у вас есть проблема с CORS. (Однако этот вопрос не связан с угловыми). Вы должны либо включить CORS для NodeJS, либо обслуживать все приложение в том же домене.

Возможные решения:

1- Включение CORS в сервере NodeJS

Вы можете включить CORS на своей стороне сервера, указав разрешенные корни в заголовке ответа. Эти строки будут включать запросы к вашему приложению из всех доменов. (добавьте это в начало определения функции.)

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 для всего домена не всегда является хорошим решением, пожалуйста, также проверьте .

2- Обслуживание ваших html файлов из приложения NodeJS

Здесь со следующими дополнениями вы будете обслуживать ваши html файлы с сервера NodeJS. (Вам больше не нужно использовать другой сервер.)

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);
});

Я также рекомендовал бы использовать ExpressJS для более богатых возможностей сервера вместо ванильного node.js http-сервера.

3. Предоставление прокси-соединения с вашего сервера html файлов на приложение nodejs

Я не знаю, что вы используете в качестве сервера для статических html файлов, но возможно наличие прокси-сервера между вашим статическим сервером на сервере приложений NodeJS.


РЕДАКТИРОВАТЬ 1

Вот базовая реализация для опции 2- Serving your html files from NodeJS application.

В этом примере я использовал ExpressJS. Статические файлы на стороне клиента подаются в общей папке, для отправки запроса на /api/upload url будет загружать файл. Вот код сервера 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);
}); 

Теперь папка public подается в корневой URL-адрес. Вот файл клиента 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>

Теперь вы можете запустить node app и попробовать его на localhost:27372 с вашим браузером.

(Вот версия gist: https://gist.github.com/aksakalli/1a56072f066d65248885)


РЕДАКТИРОВАТЬ 2

Вот базовая реализация для опции 1- Enabling CORS in NodeJS server. Я использую cors для обработки конфигурации заголовка, теперь app.js код будет выглядеть следующим образом:

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

app.use(cors());

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);
});

Ответ 2

Для первой ошибки:

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

Служба загрузки ng-file-upload Upload, которую вы используете, удаляет заголовок Content-Type, как показано здесь, перед запросом. Но метод разбора из многопартийности, похоже, требует этого. Если вы работаете из данного примера из вики, я бы посоветовал вам также использовать экспресс и многопартийность в качестве промежуточного программного обеспечения, как указано в этом примере.

Ваше приложение app.js будет выглядеть так:

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);

Для второй ошибки: Это проблема CORS, о ​​которой упоминалось. Предлагаемый app.js должен разрешить CORS из-за следующих строк:

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