NodeJS,Express,如何更新客户端以显示上传的文件

时间:2017-04-12 02:47:51

标签: javascript node.js ajax express routing

我是nodeJS,AJAX请求和路由的初学者。我按照这里的教程nodejs, express example,一切都在服务器端工作。但我不能为我的生活弄清楚如何将上传的文件(在这种情况下是图像)显示回客户端。当我请求位于单独/ uploads /目录中的文件时,我从服务器得到404响应。我假设这是一个路由问题,但我很困惑如何在快递中为上传的文件创建GET请求

app.js

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var path = require('path');
var formidable = require('formidable');
var fs = require('fs');
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));


//passport for login credentials
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy; //here we implement the strategy that passport uses

var crypto = require('crypto');
var sqlite3 = require('sqlite3');

var db = new sqlite3.Database('users.sqlite3');
var check;
db.serialize(function() {

  db.run("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT, password TEXT, salt TEXT)");
  console.log('user table created');
  db.run("DELETE FROM users");    //clear table on run for debug
  var stmt = db.prepare("INSERT INTO users VALUES (?,?,?,?)");
  stmt.run('15', 'tg', 'tg', "333");
  stmt.finalize();

  db.each("SELECT username, password, id, salt FROM users", function(err, row) {
      console.log(row.username + ": " + row.password + ": " + row.id + ': ' + row.salt);
  });
});

//db.close();


function hashPassword(password, salt) {
  console.log('password hashing');
  var hash = crypto.createHash('sha256');
  hash.update(password);
  hash.update(salt);
  return hash.digest('hex');
}

passport.use(new LocalStrategy(function(username, password, done) {
  console.log('using local strat for passport');
  db.get('SELECT salt FROM users WHERE username = ?', username, function(err, row) {
    if (!row) return done(null, false);
    var hash = hashPassword(password, row.salt);
    console.log('done hashing');
    db.get('SELECT username, id FROM users WHERE username = ? AND password = ?', username, hash, function(err, row) {
      if (!row){
        console.log('failure'); 
        return done(null, false);
      }
      console.log('success');
      return done(null, row);
    });
  });
}));

passport.serializeUser(function(user, done) {
  console.log('serializing');
  return done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  console.log('deserializing')
  db.get('SELECT id, username FROM users WHERE id = ?', id, function(err, row) {
    if (!row) return done(null, false);
    return done(null, row);
  });
});

///end user authentication

//on access to site, serve the user the login page
app.get('/', function(req, res){
  res.sendFile(path.join(__dirname, 'views/home.html'));

});

//providing routing access for success/failure on login attempt
app.post('/login', 
  passport.authenticate('local', {  successRedirect: '/home',
                                    failureRedirect: '/fail' }));

app.get('/fail', function(req,res){
  res.sendFile(path.join(__dirname, 'views/error.html'));
});

app.get('/home', function(req,res){
  res.sendFile(path.join(__dirname, 'views/home.html'));
});

app.get('/login', function(req,res){
   res.sendFile(path.join(__dirname, 'views/login.html'));
   console.log('login unsuccessful');
});

app.get('/home', function(request, response) {
        response.render('views/home');
});

app.get('/upload' , function(req, res){
    res.sendFile(__dirname + '/uploads');
});

app.post('/upload', function(req, res){

  // create an incoming form object
  var form = new formidable.IncomingForm();

  // specify that we want to allow the user to upload multiple files in a single request
  form.multiples = true;

  // store all uploads in the /uploads directory
  form.uploadDir = path.join(__dirname, '/uploads');

  // every time a file has been uploaded successfully,
  // rename it to it's orignal name
  form.on('file', function(field, file) {
    fs.rename(file.path, path.join(form.uploadDir, file.name));
  });

  // log any errors that occur
  form.on('error', function(err) {
    console.log('An error has occured: \n' + err);
  });

  // once all the files have been uploaded, send a response to the client
  form.on('end', function() {
    res.end('success');
  });

  // parse the incoming request containing the form data
  form.parse(req);

});

var server = app.listen(3000, function(){
  console.log('Server listening on port 3000');
});

upload.js

'use strict'

$('.upload-btn').on('click', function (){
    $('#upload-input').click();
    $('.progress-bar').text('0%');
    $('.progress-bar').width('0%');
});

$('#upload-input').on('change', function(){

  var files = $(this).get(0).files;

  if (files.length > 0){
    // create a FormData object which will be sent as the data payload in the
    // AJAX request
    var formData = new FormData();

    // loop through all the selected files and add them to the formData object
    for (var i = 0; i < files.length; i++) {
      var file = files[i];

      // add the files to formData object for the data payload
      formData.append('uploads[]', file, file.name);
    }

    $.ajax({
      url: '/upload',
      type: 'POST',
      data: formData,
      processData: false,
      contentType: false,
      success: function(data){
        console.log('upload success');
      },
      xhr: function() {
        // create an XMLHttpRequest
        var xhr = new XMLHttpRequest();

        // listen to the 'progress' event
        xhr.upload.addEventListener('progress', function(evt) {

          if (evt.lengthComputable) {
            // calculate the percentage of upload completed
            var percentComplete = evt.loaded / evt.total;
            percentComplete = parseInt(percentComplete * 100);

            // update the Bootstrap progress bar with the new percentage
            $('.progress-bar').text(percentComplete + '%');
            $('.progress-bar').width(percentComplete + '%');

            // once the upload reaches 100%, set the progress bar text to done
            if (percentComplete === 100) {
              $('.progress-bar').html('Done');
              console.log(formData);
              showUploadedItem(file.name);
            }


          }


        }, false);

        return xhr;
      }
    });

  }
});


function showUploadedItem (source) {
      var list = document.getElementById("image-list"),
      li   = document.createElement("li"),
      img  = document.createElement("img");
      img.src = source;
      li.appendChild(img);
      list.appendChild(li);
}

2 个答案:

答案 0 :(得分:0)

所以经过一段时间的挖掘,我发现你必须明确要求express可以将服务器静态文件发送到客户端,这是通过添加:

app.use(express.static('your_uploads_directory'));

显然,根据我和教程的实现,其他所有内容都已正确设置。

答案 1 :(得分:0)

首先,在阅读您的帖子时,您想要下载的文件似乎放在/uploads中,这是项目根目录中的文件夹。在第7行提供的app.js文件中,您有以下代码。

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

此行确保捕获所有发现遵循此公用文件夹中的文件夹结构的请求并提供该文件夹中的文件,例如,当公用文件夹包含以下文件时:/public/stylesheets/foo.css所有调用从客户端到/stylesheets/foo.css将被捕获并提供此文件。

可以在express documentation找到更多解释。

因此,要使/uploads文件夹中的文件正常工作,您可以考虑两个选项,将文件/文件夹放在/public文件夹中,或更改代码以提供指向文件的静态链接。 /uploads文件夹。

第一个选项非常简单,第二个选项需要以下一行。

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

请记住,放置这些行的oder很重要,例如,当您添加第二行时,这意味着将捕获遵循该文件夹中文件结构的所有请求,并返回该文件。然而,如果你有一个app.use,它也有另一种方式,它与其中一个静态链接中的文件具有完全相同的链接,这些链接位于静态调用之前/之上,静态调用将不会到达。您可以避免这种情况,例如,当您希望在发送文件之前发生某些事情时,因为这与问题无关,我将提供指向所谓middleware的链接。