如何使用节点 Js 将文件发送到 aws s3?
How to send a file to aws s3 using node Js?
所以我是 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 标签来提交详细信息。输入字段:
<
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;
这就是我们所做的:
我们确实在我们的环境中配置了 AWS cli 检查这个 link : 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();
});
您通过请求获得signedUrl
POST /api/items
axios
.post("http://localhost:5000/api/items", {
fileName: fileName,
fileType: fileType
})
但是,您的路由器处理 POST /api/items
请求以保存 Item
(而不是获取 S3 signedUrl)。
在您的处理程序中,您只处理成功案例 newItem.save().then(item => res.json(item));
然后当您调用带有无效正文(fileName
、fileType
)的请求时,该请求永远不会在错误情况下响应(这意味着您的客户仍在等待 "forever")
解决方案:创建一个新路由器,它会处理 get signed 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
所以我是 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 标签来提交详细信息。输入字段: <
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;
这就是我们所做的:
我们确实在我们的环境中配置了 AWS cli 检查这个 link : 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();
});
您通过请求获得signedUrl
POST /api/items
axios
.post("http://localhost:5000/api/items", {
fileName: fileName,
fileType: fileType
})
但是,您的路由器处理 POST /api/items
请求以保存 Item
(而不是获取 S3 signedUrl)。
在您的处理程序中,您只处理成功案例 newItem.save().then(item => res.json(item));
然后当您调用带有无效正文(fileName
、fileType
)的请求时,该请求永远不会在错误情况下响应(这意味着您的客户仍在等待 "forever")
解决方案:创建一个新路由器,它会处理 get signed 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