如何使用节点Js将文件发送到AWS S3?

时间:2019-05-29 15:00:07

标签: node.js reactjs amazon-s3 aws-sdk

因此,我是MERN Stack的新手,并设置了一个表格来上传图像并将其发送到AWS s3中的存储桶。我没有回应。我确定我的代码中肯定有一些错误。我没有回应。我已经按照教程进行操作,但是我的代码无法正常工作。 Server.js

const express = require("express");
const aws = require("aws-sdk");
var cors = require("cors");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const app = express();
const items = require("./routes/api/items"); // Contains all the api routes

// for uploading the images
const fs = require("fs");
const fileType = require("file-type");
const bluebird = require("bluebird");
const multiparty = require("multiparty");

// Body Parser middleware
app.use(bodyParser.json());
app.use(cors());
// DB config
const db = require("./config/keys").mongoURI;

// config for access key and id
aws.config.update({
  region: "us-east-1",
  accessKeyId: process.env.AWSAccessKeyId,
  secretAccessKey: process.env.AWSSecretKey
});

const S3_BUCKET = process.env.bucket;
console.log(S3_BUCKET);

exports.sign_s3 = (req, res) => {
  const s3 = new aws.S3(); // Create a new instance of S3
  const fileName = req.body.fileName;
  const fileType = req.body.fileType;

  // Set up the payload of what we are sending to the S3 api
  const s3Params = {
    Bucket: S3_BUCKET,
    Key: fileName,
    Expires: 500,
    ContentType: fileType,
    ACL: "public-read"
  };

  // Make a request to the S3 API to get a signed URL which we can use to upload our file
  s3.getSignedUrl("putObject", s3Params, (err, data) => {
    if (err) {
      console.log(err);
      res.json({ success: false, error: err });
    }

    // Data payload of what we are sending back, the url of the signedRequest and a URL where we can access the content after its saved.

    const returnData = {
      signedRequest: data,
      url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
    };
    // Send it all back

    res.json({ success: true, data: { returnData } });
  });
};

mongoose
  .connect(db, { useNewUrlParser: true })
  .then(() => console.log("Mongo is laoded"))
  .catch(err => console.log(err));

app.use("/api/items", items); // redirecting api routes to items

const port = process.env.PORT || 5000;

app.listen(port, () => console.log("Server started"));

我将AWS凭证存储在根目录下的.env文件中。我的表格的其他组件工作正常。仅图像未存储在aws中。 我将尝试抽象代码以删除不需要的细节。 UserForm.jsx

 handleSubmit = e => {
    e.preventDefault();
    let file = this.uploadInput.files[0];
    // Split the filename to get the name and type
    let fileParts = this.uploadInput.files[0].name.split(".");
    let fileName = fileParts[0];
    let fileType = fileParts[1];
    console.log("Preparing the upload");
    axios
      .post("http://localhost:5000/api/items", {
        fileName: fileName,
        fileType: fileType
      })
      .then(response => {
        var returnData = response.data.data.returnData;
        var signedRequest = returnData.signedRequest;
        var url = returnData.url;
        this.setState({ url: url });
        console.log("Recieved a signed request " + signedRequest);

        // Put the fileType in the headers for the upload
        var options = {
          headers: {
            "Content-Type": fileType
          }
        };
        axios
          .put(signedRequest, file, options)
          .then(result => {
            console.log("Response from s3");
            this.setState({ success: true });
          })
          .catch(error => {
            alert("ERROR " + JSON.stringify(error));
          });
      })
      .catch(error => {
        alert(JSON.stringify(error));
      });

    // update ends
    const users = {
      name: this.state.name,
      contact: this.state.contact,
      company: this.state.company,
      mail: this.state.mail,
      key: this.state.key,
      apps_no: this.state.apps_no
    };

    axios
      .post(
        "http://localhost:5000/api/items",
        {
          name: users.name,
          contact_no: users.contact,
          company_name: users.company,
          key: users.key,
          mail: users.mail,
          apps_no: users.apps_no
        },
        {
          headers: {
            "content-type": "application/json"
          }
        }
      )
      .then(res => {
        console.log("Post submitted with response " + res.status);
        console.log("Mail: " + users.mail);
      })
      .catch(function(error) {
        console.log(error);
      });

    this.props.history.push("/form-submitted");
  };

  componentDidMount() {
    axios.get("http://localhost:5000/api/items").then(resp => {
      console.log(resp.data);
    });
  }

在渲染功能中,我正在表单标签中使用onClick标记来提交详细信息。输入栏位: << / p>

center>
            <h1>UPLOAD A FILE</h1>
            {this.state.success ? <Success_message /> : null}
            <input
              onChange={this.handleFileChange.bind(this)}
              ref={ref => {
                this.uploadInput = ref;
              }}
              type="file"
            />
            <br />

控制台:

Array(22)
UserForm.jsx:54 Preparing the upload
UserForm.jsx:115 Post submitted with response 200

我的代码显然有很多错误。帮助将不胜感激。 编辑: items.js-

const express = require("express");
const router = express.Router();

// Item model
const Item = require("../../models/Item");

// Routes
// @get API item get all items
// make a get req
router.get("/", (req, res) => {
  Item.find().then(items => res.json(items));
});

// @get Api item POST all items
// make a post req
// create an item
router.post("/", (req, res) => {
  const newItem = new Item({
    name: req.body.name,
    contact_no: req.body.contact_no,
    company_name: req.body.company_name,
    key: req.body.key,
    mail: req.body.mail,
    apps_no: req.body.apps_no
  });

  newItem.save().then(item => res.json(item));
});

// @del api item.
// delete request
router.delete("/:id", (req, res) => {
  Item.findById(req.params.id)
    .then(item => item.remove().then(() => res.json({ success: true })))
    .catch(err => res.status(404).json({ success: false }));
});

module.exports = router;

2 个答案:

答案 0 :(得分:0)

这就是我们要做的:

我们确实在环境中配置过AWS cli,请检查以下链接:https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html,实时运行您的项目以安全的方式配置和读取所需的AWS密钥,但不要将任何密钥存储在.env文件或脚本之后的代码如下:

const AWS = require('aws-sdk');
const s3 = new AWS.S3();

let putParams = {
            Body: fileCotent, 
            Bucket: s3BucketName, 
            Key: fileName,
            ContentType:'image/png'

        };
        s3.putObject(putParams, function(err, data) {
            if (err) console.log(err, err.stack); 
            else     console.log(data); 
            done();

        });

答案 1 :(得分:0)

您通过请求得到signedUrl POST /api/items

axios
  .post("http://localhost:5000/api/items", {
    fileName: fileName,
    fileType: fileType
  })

但是,您的路由器处理POST /api/items来保存Item的请求(而不是获取S3signedUrl)。

在处理程序中,您仅处理成功案例newItem.save().then(item => res.json(item));,然后在调用无效正文(fileNamefileType)的请求时,该请求绝不会在错误情况下响应(此表示您的客户仍然“永远等待”)

解决方案:创建一个新路由器,它将处理获取签名的URL请求

  • 更新您的客户端Server.js

    app.post('/signed-url', exports.sign_s3); // this line

    mongoose

    ...

  • 更新客户端UserForm.jsx

    console.log("Preparing the upload");

    axios

    .post("http://localhost:5000/signed-url") // instead of http://localhost:5000/api/items