Как отправить файл в aws s3, используя узел Js? - PullRequest
1 голос
/ 29 мая 2019

Итак, я новичок в стеке MERN и настроил форму для загрузки изображения и отправки его в мое ведро в 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 голосов
/ 30 мая 2019

Вы получаете signedUrl по запросу POST /api/items

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

, но ваш маршрутизатор обрабатывает POST /api/items запрос на сохранение Item (вместо get S3 signatureUrl).

В вашем обработчике вы обрабатываете только случай успеха newItem.save().then(item => res.json(item));, тогда когда вы вызываете запрос с недопустимым телом (fileName, fileType), запрос никогда не отвечает в случае ошибки (это означает, что ваш клиент все еще ждет "навсегда"")

Решение: создайте новый маршрутизатор, он будет обрабатывать получение подписанного 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

0 голосов
/ 29 мая 2019

Это то, что мы сделали:

Мы настроили 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();

        });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...