NodeJS Knox Formidable results in a 400, File not Uploaded to S3 Bucket

梦想的初衷 提交于 2021-01-07 06:31:58

问题


I want to use formidable and knox to upload files to AWS S3 bucket, but I get a 400 each time and the file is not uploaded. My code is similar to this: nodejs knox put to s3 results in a 403, the only difference is that the first argument of my readFile is from my windows temp folder, I tried the solution in the comment by ensuring my bucket name is only small letters but this also did not work. Please help if you can, thank you. My codes are below:

App.js

const express = require("express"),
  path = require("path"),
  config = require("./config"),
  knox = require("knox"),
  fs = require("fs"),
  os = require("os"),
  formidable = require("formidable"),
  gm = require("gm"),
  mongoose = require("mongoose");

mongoose.connect(config.dbURL, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

const app = express();

app.set("views", path.join(__dirname, "views"));
app.engine("html", require("hogan-express"));
app.set("view engine", "html");

app.use(express.static(path.join(__dirname, "public")));
app.set("port", process.env.PORT || 3000);
app.set("host", config.host);

let knoxClient = knox.createClient({
  key: config.S3AccessKey,
  secret: config.S3Secret,
  bucket: config.S3Bucket,
});

const server = require("http").createServer(app);
const io = require("socket.io")(server);

require("./routers")(
  express,
  app,
  formidable,
  fs,
  os,
  gm,
  knoxClient,
  mongoose,
  io
);

server.listen(app.get("port"), function () {
  console.log("PhotoGRID Running on port: " + app.get("port"));
});

Router(index.js)

module.exports = (
  express,
  app,
  formidable,
  fs,
  os,
  gm,
  knoxClient,
  mongoose,
  io
) => {
  //os.tmpDir = os.tmpdir;
  let Socket;

  io.on("connection", function (socket) {
    Socket = socket;
  });

  const singleImage = new mongoose.Schema({
    filename: {
      type: String,
      require: true,
    },
    votes: {
      type: Number,
      require: true,
    },
  });

  let singleImageModel = mongoose.model("singleImage", singleImage);
  let router = express.Router();

  router.get("/", function (req, res, next) {
    res.render("index", { host: app.get("host") });
  });

  router.post("/upload", function (req, res, next) {
    // File upload

    function generateFilename(filename) {
      let ext_regex = /(?:\.([^.]+))?$/;
      let ext = ext_regex.exec(filename)[1];
      let date = new Date().getTime();
      let charBank = "abcdefghijklmnopqrstuvwxyz";
      let fstring = "";
      for (let i = 0; i < 15; i++) {
        fstring += charBank[parseInt(Math.random() * 26)];
      }
      return (fstring += date + "." + ext);
    }

    let tmpFile, nFile, fName;
    let newForm = new formidable.IncomingForm();
    newForm.keepExtensions = true;
    newForm.parse(req, function (err, fields, files) {
      tmpFile = files.upload.path;
      fName = generateFilename(files.upload.name);
      nFile = os.tmpDir() + "/" + fName;
      res.writeHead(200, { "Content-type": "text/plain" });
      res.end();
    });

    newForm.on("end", function () {
      fs.rename(tmpFile, nFile, function () {
        // Resize the image and upload this file into the S3 bucket
        gm(nFile)
          .resize(300)
          .write(nFile, function () {
            // Upload to the S3 Bucket
            fs.readFile(nFile, function (err, buf) {
              let req = knoxClient.put(fName, {
                "Content-Length": buf.length,
                "Content-Type": "image/jpg",
              });

              req.on("response", function (res) {
                if (res.statusCode == 200) {
                  //This means that the file is in the S3 Bucket
                  console.log(fName + " is in the S3 bucket");

                  let newImage = new singleImageModel({
                    filename: fName,
                    votes: 0,
                  }).save();

                  Socket.emit("status", { msg: "Saved!!", delay: 3000 });
                  Socket.emit("doUpdate", {});

                  // Delete the Local file
                  fs.unlink(nFile, function () {
                    console.log("Local file deleted!");
                  });
                } else {
                  console.log(
                    err +
                      fName +
                      " did not get to the database or S3 bucket so " +
                      nFile +
                      " was not deleted " +
                      res.statusCode
                  );
                }
              });

              req.end(buf);
            });
          });
      });
    });
  });

  app.use("/", router);
};

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>PhotoGrid</title>
    <link rel="stylesheet" href="../css/main.css" />
    <script src="http://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script src="../js/photogrid_utils.js"></script>
    <script>
      $(function () {
        let host = "{{host}}";

        $(document).on("click", "#doUpload", function () {
          uploadNow();
        });

        let socket = io(host);

        socket.on("status", function (data) {
          showStatus(data.msg, data.delay);
        });

        socket.on("doUpdate", function () {
          renderList();
        });

        function uploadNow() {
          let uploadURL = host + "/upload";
          let uploadFile = $(".uploadPic");
          if (uploadFile.val() != "") {
            let form = new FormData();
            form.append("upload", uploadFile[0].files[0]);
            // Perform the AJAX POST request and send the file
            ajax({
              method: "post",
              url: uploadURL,
              success: function () {
                $(".progress").fadeOut(200);
                uploadFile.val("");
              },
              progress: function (e) {
                if (e.lengthComputable) {
                  let perc = Math.round((e.loaded * 100) / e.total);
                  $(".progress").css("width", perc + "%");
                }
              },
              payload: form,
            });
          }
        }
      });
    </script>
  </head>
  <body>
    <div class="container">
      <div class="topDeck">
        <div class="logo">
          <a href="{{host}}">
            <h1>PhotoGRID</h1>
          </a>
        </div>
        <div class="controls">
          <input type="file" name="uploadPic" class="uploadPic" />
          <button id="doUpload">Upload</button>
          <div class="progressBarDiv">
            <div class="progress"></div>
          </div>
          <h5 class="status"></h5>
        </div>
      </div>
      <div class="gallery">
        <ul>
          <!-- Repeat the following <li> structure for every image -->
          <li>
            <div class="overlay">
              <div class="voteCtrl">
                <a href="#" class="voteUp">
                  <img
                    src="../images/voteup.png"
                    alt="Click Here to Vote Up !"
                  />
                  <h4>100</h4>
                </a>
              </div>
            </div>
            <div class="imageHolder">
              <img src="../images/someimage.jpg" alt="" />
            </div>
          </li>
          <!-- End Repeat -->
        </ul>
      </div>
    </div>
  </body>
</html>


回答1:


I couldn't get my code to work with knox, I kept getting a 400 statusCode and my files were not being uploaded to S3. So I used aws-sdk and it worked like magic. My files are being uploaded and saved to my mongo database. For those who might bump into the same problem, this is what I did:

const { config } = require("aws-sdk");

module.exports = (express, app, formidable, fs, os, gm, s3, mongoose, io) => {
  //os.tmpDir = os.tmpdir;
  let Socket;

  io.on("connection", function (socket) {
    Socket = socket;
  });

  const singleImage = new mongoose.Schema({
    filename: {
      type: String,
      require: true,
    },
    votes: {
      type: Number,
      require: true,
    },
  });

  let singleImageModel = mongoose.model("singleImage", singleImage);
  let router = express.Router();

  router.get("/", function (req, res, next) {
    res.render("index", { host: app.get("host") });
  });

  router.post("/upload", function (req, res, next) {
    // File upload

    function generateFilename(filename) {
      let ext_regex = /(?:\.([^.]+))?$/;
      let ext = ext_regex.exec(filename)[1];
      let date = new Date().getTime();
      let charBank = "abcdefghijklmnopqrstuvwxyz";
      let fstring = "";
      for (let i = 0; i < 15; i++) {
        fstring += charBank[parseInt(Math.random() * 26)];
      }
      return (fstring += date + "." + ext);
    }

    let tmpFile, nFile, fName;
    let newForm = new formidable.IncomingForm();
    newForm.keepExtensions = true;
    newForm.parse(req, function (err, fields, files) {
      tmpFile = files.upload.path;
      fName = generateFilename(files.upload.name);
      nFile = os.tmpDir() + "\\" + fName;
      res.writeHead(200, { "Content-type": "image/JPG" });
      res.end();
    });

    newForm.on("end", function () {
      fs.rename(tmpFile, nFile, function () {
        // Resize the image and upload this file into the S3 bucket
        gm(nFile)
          .resize(300)
          .write(nFile, function () {
            // Upload to the S3 Bucket
            /* fs.readFile(nFile, function (err, buf) {
              let req = knoxClient.put(fName, {
                "Content-Length": buf.length,
                "Content-Type": "image/JPG",
                "x-amz-acl": "public-read",
              }); */

            const fileContent = fs.readFileSync(nFile);

            const params = {
              Bucket: require("../config").S3Bucket,
              Key: fName,
              Body: fileContent,
            };

            s3.upload(params, function (err, data) {
              // Delete the Local file
              fs.unlink(nFile, function (err) {
                console.log("Local file deleted!");
                if (err) {
                  console.error(err);
                }
              });
              console.log("PRINT FILE: ", fName);
              if (err) {
                console.log("ERROR MSG: ", err);
                res.status(500).send(err);
              } else {
                //This means that the file is in the S3 Bucket
                console.log(fName + " is in the S3 bucket");

                let newImage = new singleImageModel({
                  filename: fName,
                  votes: 0,
                }).save();

                Socket.emit("status", { msg: "Saved!!", delay: 3000 });
                Socket.emit("doUpdate", {});

                res.status(200).end();
              }
            });

            /*               req.on("response", function (res) {
                if (res.statusCode == 200) {
                  

                } else {
                  console.log(
                    err +
                      fName +
                      " did not get to the database or S3 bucket so " +
                      nFile +
                      " was not deleted " +
                      res.statusCode
                  );
                  console.log(res.statusMessage);
                }
              }); */

            // req.end(buf);
            //     });
          });
      });
    });
  });

  app.use("/", router);
};



来源:https://stackoverflow.com/questions/65225966/nodejs-knox-formidable-results-in-a-400-file-not-uploaded-to-s3-bucket

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!