我正在使用multer从我的react客户端上传图像。所有图像都在存储中,只是没有显示出来。图像正在存储,但没有出现在反应中。处于设置状态只是不显示。我可以在后端的images文件夹中看到它们,所以我知道multer正在工作。
这是我的反应组件
class AddNewDish extends Component {
constructor(props){
super(props)
this.state = {
name: '',
imageUrl: '',
description: ''
}
}
createDishHandler = (event) => {
event.preventDefault()
const fd = new FormData();
fd.append('name', this.state.name)
fd.append('imageUrl', this.state.imageUrl, this.state.imageUrl.name)
fd.append('description', this.state.description)
axios.post('http://localhost:8080/add-new-dish', fd,)
.then(res => {
console.log(res, 'res')
})
this.props.history.push('/')
}
onChange = (e) => {
switch(e.target.name) {
case 'imageUrl':
this.setState({imageUrl: e.target.files[0]});
break;
default:
this.setState({[e.target.name]: e.target.value})
}
console.log(e)
}
render () {
console.log(this.state.imageUrl, 'in imgUrl')
return (
<div>
<form onSubmit={this.createDishHandler}>
<input
label='Name'
onChange={this.onChange}
name='name'
type='text'
placeholder='Enter Dish Name'
value={this.state.name}
/>
< input
label='Dish Image'
onChange={this.onChange}
name='imageUrl'
type='file'
placeholder='Enter Dish Image'
// value={this.state.imageUrl}
/>
<input
label='Description'
onChange={this.onChange}
name='description'
placeholder='Enter Dish Description'
type='text'
value={this.state.description}
/>
<img src={this.state.imageUrl}/>
<button>Submit Dish</button>
</form>
</div>
)
}
};
export default AddNewDish
一个后端
const multer = require('multer');
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public')
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + path.extname(file.originalname))
}
});
const fileFilter = (req, file, cb) => {
if(
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true)
} else {
cd(null, false)
}
}
exports.upload = multer({
storage: fileStorage,
fileFilter: fileFilter
})
.single('imageUrl')
这就是我的路线称呼
exports.postADish = async ( req, res,) => {
console.log(req.file, 'in req.file')
try {
const { name, description } = req.body;
const imageUrl = req.file.path
const newDish = await dish.postNewDish({name, description, imageUrl})
res.status(201).json(`new dish added`)
} catch (err) {
res.status(500).json(`Error posting dish`)
console.log(err)
}
};
我如何使用上传中间件
router.post('/add-new-dish', dishController.upload, dishController.postADish);
公开文件夹
app.use('/public', express.static('public'))
这就是我试图在前端的索引路由中显示图像的方式
class App extends Component {
constructor () {
super()
this.state = {
data: []
}
}
componentDidMount() {
axios
.get(`http://localhost:8080/`)
.then(res => {
console.log(res, 'response')
this.setState({
data: res.data.dishData
})
})
.catch(err => {
console.log(err)
})
}
render() {
console.log(this.state.data)
return (
<div className="App">
<Nav
<Route
exact path ='/'
render={props =>
<Home
{...props}
dishes={this.state.data}
/>
}
/>
我的状态如下
{id: 7, name: "test dish", imageUrl: "public/2019-04-20T22:52:09.900Z-20190411_112505.jpg", description: "test description"}
我要取回imageUrl并在home组件中使用它
const Home = (props) => {
return (
<DishWrapper>
<DishContent>
{props.dishes.map(dish => {
console.log(dish, 'in dish')
return (
<Dish key={dish.id}>
<h3>{dish.name}</h3>
<img src={ `public/${dish.imageUrl}`} alt={dish.name}/>
<h5>{dish.description}</h5>
</Dish>
)
})}
</DishContent>
</DishWrapper>
)
};
export default Home
在后端,我得到的像这样
exports.getDishes = async (req, res) => {
try {
const dishData = await dish.getDishes()
if(!dishData) {
res.status(404).json(`No dishes available at this time`)
} else {
res.status(200).json({
dishData,
})
}
} catch (err) {
res.status(500)
console.log(err)
}
};
答案 0 :(得分:0)
因此,要在上传之前查看图像,您需要首先使用FileReader,这是一个javascript对象,可让Web应用程序异步读取文件内容。这将为您提供映像的base64版本,您可以将其添加到映像src中。因此,您可以在onChange函数中执行此操作,其外观类似于以下内容:
onChange = (e) => {
switch(e.target.name) {
case 'imageUrl':
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = () => {
this.setState({
imageUrl: file,
imgBase64: reader.result
})
};
reader.readAsDataURL(file);
break;
default:
this.setState({[e.target.name]: e.target.value})
}
}
在此示例中,我将向状态添加imgBase64
键,并向其添加base64值,但是您可以使用任何喜欢的名称,只需确保将其添加到状态对象即可。
然后要查看它,可以使用此值作为图像src,如下所示:
<img src={this.state.imgBase64}/>
此后,当您将图像提交给multer时,您需要返回图像的文件名,以便您可以在上传后访问它,因此在您的路线中就可以访问它,因为好像您在登录时取回了正确的文件名即可将其返回到axios调用,然后再使用它。因此,在您的路由中,只需发送回一个json对象并使用它即可。因此,请发送以下内容,而不是res.status(201).json(
添加新菜)
:
res.status(201).json({
msg: 'new dish added',
imageUrl: req.file.filename
})
,然后您的axios调用将收到此json对象,之后您可以像这样在前端访问
createDishHandler = (event) => {
event.preventDefault()
const fd = new FormData();
fd.append('name', this.state.name)
fd.append('imageUrl', this.state.imageUrl, this.state.imageUrl.name)
fd.append('description', this.state.description)
axios.post('http://localhost:8080/add-new-dish', fd,)
.then(res => {
//you can set your res.data.imageUrl to your state here to use it
console.log('Success Message: ' + res.data.msg + ' - Image File Name: ' + res.data.imageUrl)
})
this.props.history.push('/')
}
但是在上面的功能中,我看到您在上传时推送了另一页。因此,如果您推送到另一个页面,那么显然您将不再使用此状态,因此您可能需要在那时从新页面的数据库中检索它。
无论如何,我希望这会有所帮助,如果您有任何疑问,请告诉我。
P.S。我只是想让您知道,您可能希望在混合模式上传中使用Date.now() + path.extname(file.originalname)
而不是new Date().toISOString() + '-' + path.extname(file.originalname)
,这样看起来有点干净,没有冒号和破折号,但这不是必须的。
编辑:
因此,如果您要使用express为静态文件夹提供服务,则就像我在下面的前面的评论中所说,您将必须使用绝对URL来访问您的内容。 React无法访问客户端中公共文件夹之外具有相对路径的任何内容。因此,如果在后端根目录中将有一个名为images的文件夹,那么在multer中,您可以将目标设置为'images'
并表示您将提供静态文件夹app.use(express.static('images'))
并通过您的图像进行访问您将需要使用绝对网址
<img src={ `http://localhost:8080/${imageUrl}`} alt={dish.name}/>