Node.JS

File Upload

The following code example illustrates how to handle file upload on your server using Node.JS as a server-side language. For step by step explanation of the upload flow see file upload concept.

Dependencies

The node.JS file upload example needs the following dependencies:

Make sure that you run npm install, or if you are using bower run bower install

Frontend

The main index page

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">

  <!-- Include Editor style. -->
  <link href="https://cdn.jsdelivr.net/npm/froala-editor@3.0.0-beta.1/css/froala_editor.pkgd.min.css" rel="stylesheet" type="text/css" />
</head>

<body>
  <div class="sample">
    <h2>File upload example.</h2>
    <form>
      <textarea id="edit" name="content"></textarea>
    </form>
  </div>

  <!-- Include Editor JS files. -->
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/froala-editor@3.0.0-beta.1/js/froala_editor.pkgd.min.js"></script>

  <!-- Initialize the editor. -->
  <script>
    new FroalaEditor('#edit', {
      // Set the file upload URL.
      fileUploadURL: 'file_upload',

      fileUploadParams: {
        id: 'my_editor'
      }
    })
  </script>
</body>
</html>

Backend

server.js file will handle the server part for Node.JS

The server.js file will be a handle for both image and file upload

// Include required libs
var express = require("express");
var app = express();
var bodyParser = require("body-parser")
var path = require("path");
var fs = require("fs");
var upload_file = require("./file_upload.js");
var upload_image = require("./image_upload.js");

app.use(express.static(__dirname + "/"));
app.use(bodyParser.urlencoded({ extended: false }));

app.get("/", function(req, res) {
  res.sendFile(__dirname + "/index.html");
});


// File POST handler.
app.post("/file_upload", function (req, res) {
  upload_file(req, function(err, data) {

    if (err) {
      return res.status(404).end(JSON.stringify(err));
    }

    res.send(data);
  });
});

// Image POST handler.
app.post("/image_upload", function (req, res) {
  upload_image(req, function(err, data) {

    if (err) {
      return res.status(404).end(JSON.stringify(err));
    }

    res.send(data);
  });
});


// Create folder for uploading files.
var filesDir = path.join(path.dirname(require.main.filename), "uploads");
if (!fs.existsSync(filesDir)){
  fs.mkdirSync(filesDir);
}

// Init server.
app.listen(3000, function () {
  console.log("Example app listening on port 3000!");
});

file_upload.js file will do the upload part. It has basic file format validations this can be easily extended.

The uploads directory must be set to a valid location before any uploads are made. The path can be any folder that is accessible and write available.

After processing the uploaded image, if it passes the validation, the server will respond with a JSON object containing a link to the uploaded file.

E.g.: {"link":"http://server_address/uploads/name_of_file"}

var Busboy = require("busboy");
var path = require("path");
var fs = require("fs");
var sha1 = require("sha1");

// Gets a filename extension.
function getExtension(filename) {
  return filename.split(".").pop();
}

// Test if a file is valid based on its extension and mime type.
function isFileValid(filename, mimetype) {
  var allowedExts = ["txt", "pdf", "doc"];
  var allowedMimeTypes = ["text/plain", "application/msword", "application/x-pdf", "application/pdf"];

  // Get file extension.
  var extension = getExtension(filename);

  return allowedExts.indexOf(extension.toLowerCase()) != -1  &&
     allowedMimeTypes.indexOf(mimetype) != -1;
}

function upload (req, callback) {
  // The route on which the file is saved.
  var fileRoute = "/uploads/";

  // Server side file path on which the file is saved.
  var saveToPath = null;

  // Flag to tell if a stream had an error.
  var hadStreamError = null;

  // Used for sending response.
  var link = null;

  // Stream error handler.
  function handleStreamError(error) {
    // Do not enter twice in here.
    if (hadStreamError) {
      return;
    }

    hadStreamError = error;

    // Cleanup: delete the saved path.
    if (saveToPath) {
      return fs.unlink(saveToPath, function (err) {
        return callback(error);
      });
    }

    return callback(error);
  }

  // Instantiate Busboy.
  try {
    var busboy = new Busboy({ headers: req.headers });
  } catch(e) {
    return callback(e);
  }

  // Handle file arrival.
  busboy.on("file", function(fieldname, file, filename, encoding, mimetype) {
    // Check fieldname:
    if ("file" != fieldname) {
      // Stop receiving from this stream.
      file.resume();

      return callback("Fieldname is not correct. It must be "file".");
    }

    // Generate link.
    var randomName = sha1(new Date().getTime()) + "." + getExtension(filename);
    link = fileRoute + randomName;

    // Generate path where the file will be saved.
    var appDir = path.dirname(require.main.filename);
    saveToPath = path.join(appDir, link);

    // Pipe reader stream (file from client) into writer stream (file from disk).
    file.on("error", handleStreamError);

    // Create stream writer to save to file to disk.
    var diskWriterStream = fs.createWriteStream(saveToPath);
    diskWriterStream.on("error", handleStreamError);

    // Validate file after it is successfully saved to disk.
    diskWriterStream.on("finish", function() {
      // Check if file is valid
      var status = isFileValid(saveToPath, mimetype);

      if (!status) {
        return handleStreamError("File does not meet the validation.");
      }

      return callback(null, {link: link});
    });

    // Save file to disk.
    file.pipe(diskWriterStream);
  });

  // Handle file upload termination.
  busboy.on("error", handleStreamError);
  req.on("error", handleStreamError);

  // Pipe reader stream into writer stream.
  return req.pipe(busboy);
}

module.exports = upload;