node.js - 如何延迟将图像上传到 S3?
问题描述
我正在开发一个“uploadProductPage”,我可以在其中输入一些保存在 mongoDB 中的数据并上传一张上传到 Amazon S3 的照片。我正在使用 dropzone 进行图像上传过程,当我选择一个文件时,它会立即上传到 S3。如果可能的话,我想延迟上传过程,直到按下“提交”按钮。
我的代码如下:
文件上传.js
import React, { useState } from 'react'
import Dropzone from 'react-dropzone';
import { Icon } from 'antd';
import Axios from 'axios';
import download from './download.jpeg'
function FileUpload(props) {
const [Images, setImages] = useState([])
const onDrop = (files) => {
let formData = new FormData();
const config = {
header: {
'accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.8',
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`
}
}
formData.append("profileImage", files[0])
//save the Image we chose inside the Node Server
Axios.post('/api/photo/profile-img-upload', formData, config)
.then(response => {
if (response.data) {
alert('Saved')
setImages([...Images, response.data.imageName])
props.refreshFunction([...Images, response.data.image])
} else {
alert('Failed to save the Image in Server')
}
})
}
const onDelete = (image) => {
const currentIndex = Images.indexOf(image);
let newImages = [...Images]
newImages.splice(currentIndex, 1)
setImages(newImages)
props.refreshFunction(newImages)
}
return (
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Dropzone
onDrop={onDrop}
multiple={false}
maxSize={800000000}
>
{({ getRootProps, getInputProps }) => (
<div style={{
width: '300px', height: '240px', border: '1px solid lightgray',
display: 'flex', alignItems: 'center', justifyContent: 'center'
}}
{...getRootProps()}
>
{console.log('getRootProps', { ...getRootProps() })}
{console.log('getInputProps', { ...getInputProps() })}
<input {...getInputProps()} />
<Icon type="plus" style={{ fontSize: '3rem' }} />
</div>
)}
</Dropzone>
<div style={{ display: 'flex', width: '300px', height: '300px'}}>
{Images.map((image, index) => (
<div onClick={() => onDelete(image)}>
<img style={{ minWidth: '300px', width: '300px', height: '240px' }} src={download} alt={`productImg-${index}`} />
</div>
))}
</div>
</div>
)
}
export default FileUpload
photo.js(路由器)
const express = require( 'express' );
const multer = require('multer');
const url = require('url');
const aws = require("aws-sdk");
const multerS3 = require("multer-s3");
const { auth } = require("../middleware/auth");
const path = require('path');
const router = express.Router();
const s3 = new aws.S3({
accessKeyId: '',
secretAccessKey: '',
Bucket: 'uploads-111'
});
aws.config.update({
secretAccessKey: process.env.S3_ACCESS_SECRET,
accessKeyId: process.env.S3_ACCESS_KEY,
region: "us-east-2",
});
const profileImgUpload = multer({
storage: multerS3({
s3: s3,
bucket: 'uploads-111',
acl: 'public-read',
key: function (req, file, cb) {
cb(null, path.basename( file.originalname, path.extname( file.originalname ) ) + '-' + Date.now() + path.extname( file.originalname ) )
}
}),
limits:{ fileSize: 2000000 }, // In bytes: 2000000 bytes = 2 MB
fileFilter: function( req, file, cb ){
checkFileType( file, cb );
}
}).single('profileImage');
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb('Error: Images Only!');
}
if( mimetype && extname ){
return cb( null, true );
} else {
cb( 'Error: Images Only!' );
}
}
router.post( '/profile-img-upload', ( req, res ) => {
profileImgUpload( req, res, ( error ) => {
// console.log( 'requestOkokok', req.file );
// console.log( 'error', error );
if( error ){
console.log( 'errors', error );
res.json( { error: error } );
} else {
// If File not found
if( req.file === undefined ){
console.log( 'Error: No File Selected!' );
res.json( 'Error: No File Selected' );
} else {
// If Success
const imageName = req.file.key;
const imageLocation = req.file.location;
res.json( {
image: imageName,
location: imageLocation
} );
}
}
});
});
module.exports = router;
上传ProductPage.js
import React, { useState } from 'react'
import { Typography, Button, Form, message, Input, Icon } from 'antd';
import FileUpload from '../../utils/FileUpload'
import Axios from 'axios';
const { Title } = Typography;
const { TextArea } = Input;
const Continents = [
{ key: 1, value: "1" },
{ key: 2, value: "2" },
{ key: 3, value: "3" },
{ key: 4, value: "4" },
{ key: 5, value: "5" },
{ key: 6, value: "6" },
{ key: 7, value: "7" }
]
function UploadProductPage(props) {
const [TitleValue, setTitleValue] = useState("")
const [DescriptionValue, setDescriptionValue] = useState("")
const [PriceValue, setPriceValue] = useState(0)
const [ContinentValue, setContinentValue] = useState([])
const [Images, setImages] = useState([])
const onTitleChange = (event) => {
setTitleValue(event.currentTarget.value)
}
const onDescriptionChange = (event) => {
setDescriptionValue(event.currentTarget.value)
}
const onPriceChange = (event) => {
setPriceValue(event.currentTarget.value)
}
const onContinentsSelectChange = (event) => {
setContinentValue(event.currentTarget.value)
}
const updateImages = (newImages) => {
setImages(newImages)
}
const onSubmit = (event) => {
event.preventDefault();
if (!TitleValue || !DescriptionValue || !PriceValue ||
!ContinentValue || !Images) {
return alert('fill all the fields first!')
}
const variables = {
writer: props.user.userData._id,
title: TitleValue,
description: DescriptionValue,
price: PriceValue,
images: Images,
continents: ContinentValue,
}
Axios.post('/api/product/uploadProduct', variables)
.then(response => {
if (response.data.success) {
alert('Product Successfully Uploaded')
props.history.push({
pathname: "/user/cart",
state: {
data: variables,
},
})
} else {
alert('Failed to upload Product')
}
})
}
return (
<div style={{ maxWidth: '700px', margin: '2rem auto' }}>
<div style={{ textAlign: 'center', marginBottom: '2rem' }}>
<Title level={2}> Upload Prompt </Title>
</div>
<Form onSubmit={onSubmit} >
{/* DropZone */}
<FileUpload refreshFunction={updateImages} />
<br />
<br />
<label>Subject</label>
<Input
onChange={onTitleChange}
value={TitleValue}
/>
<br />
<br />
<label>Title</label>
<Input
onChange={onDescriptionChange}
value={DescriptionValue}
/>
<br />
<br />
<label>Pages</label>
<Input
onChange={onPriceChange}
value={PriceValue}
type="number"
/>
<br /><br />
<label>Due Date</label>
<br /><br />
<Input onChange={onContinentsSelectChange} value={ContinentValue}
type="date"
/>
<br />
<br />
<Button
onClick={onSubmit}
>
Submit
</Button>
</Form>
</div>
)
}
export default UploadProductPage
解决方案
推荐阅读
- powershell - 用于在事件查看器中搜索任务名称的 Windows 10 PowerShell 脚本
- php - 循环遍历数组中的会话并保存到数据库
- eclipse - Kotlin 在 Eclipse 或命令行中编译 java 12 和 kotlin
- javascript - 弹出警报用户在文本框中写的内容
- sql - 将“预定义”列表构建为表格
- html - 如何胜过 chrome 的用户代理样式表选择器“-internal-autofill-selected”?
- scala - Spark:架构为空
- php - PHP $_SESSION 参数由服务器重置?
- c# - 使用 VB.Net 从 XML 中删除基于值的属性值
- javascript - discord.js bot await 仅在异步函数中有效