【问题标题】:NodeJS, Express, how to update client side to display uploaded fileNodeJS,Express,如何更新客户端以显示上传的文件
【发布时间】:2017-09-07 15:14:57
【问题描述】:

我是 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');
});

上传.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);
}

【问题讨论】:

  • File 对象默认没有.path 属性。

标签: javascript node.js ajax express routing


【解决方案1】:

所以在研究了一段时间后,我发现您必须明确请求 express 可以将静态文件发送到客户端,这是通过添加来完成的:

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

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

【讨论】:

    【解决方案2】:

    首先,在阅读您的帖子时,您要下载的文件似乎放在/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')));
    

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

    【讨论】:

      猜你喜欢
      • 2017-03-20
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2021-04-02
      • 2018-03-17
      • 1970-01-01
      • 2015-06-24
      • 1970-01-01
      相关资源
      最近更新 更多