node.js - 使用 react.js node.js express.js REST API 将配置文件图片上传到 sqlite DB
问题描述
所以我试图通过 react.js 应用程序将配置文件图像上传到作为 REST API 运行的后端,使用 node.js express.js 和 sqlite 作为数据库。
但不知何故,我找不到任何教程对我有用。不过我一定很近。所以我现在拥有的是:
我的路线如下所示:
playerRoutes.js:
const express = require('express');
const router = express.Router();
const multer = require('multer');
const uuidv4 = require('uuid/v4');
const upload_dir = './uploads';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, upload_dir);
},
filename: (req, file, cb) => {
cb(null, `${uuidv4()}-${file.filename.toLowerCase}`);
}
});
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (
file.mimetype == 'image/png' ||
file.mimetype == 'image/jpg' ||
file.mimetype == 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Only .png, .jpg and .jpeg format allowed!'));
}
}
});
const { playerController } = require('../controller');
router.get('/', playerController.getAllPlayer);
router.get('/:id', playerController.getSpecificPlayer);
router.post('/', upload.single('profileImg'), playerController.createPlayer);
router.put('/:id', playerController.updatePlayer);
router.delete('/:id', playerController.deletePlayer);
module.exports = router;
所以关键点是它的设置storage
告诉在哪里上传+文件过滤器upload
,对吧?
哪个route.post
将`upload.single('profileImg'),对吗?该路线将包括我用于创建 Player 的控制器,可以在此处找到:
playerController.js
const { Player } = require('../models');
module.exports = {
getAllPlayer(req, res) {
return Player.findAll({
attributes: ['id', 'name', 'nickname', 'profileImg']
})
.then(players => res.status(200).send(players))
.catch(err => res.status(400).send(err));
},
getSpecificPlayer(req, res) {
return Player.findByPk(req.params.id, {
attributes: ['id', 'name', 'nickname', 'profileImg']
}).then(player => {
if (!player) {
return res.status(404).send({
message: `Player with id ${req.params.id} not found`
});
}
return res.status(200).send(player);
});
},
createPlayer(req, res) {
console.log(req.file);
return Player.create({
name: req.body.name,
nickname: req.body.nickname
})
.then(player => res.status(201).send(player))
.catch(err => res.status(400).send(err));
},
updatePlayer(req, res) {
return Player.findByPk(req.params.id, {
attributes: ['id', 'name', 'nickname', 'profileImg']
})
.then(player => {
if (!player) {
return res.status(404).send({
message: `Player with id ${req.params.id} not found`
});
}
return player
.update({
name: req.body.name || player.name,
nickname: req.body.nickname || player.nickname,
profileImg: req.body.profileImg || player.profileImg
})
.then(() => res.status(200).send(player))
.catch(err => res.status(400).send(err));
})
.catch(err => res.status(400).send(err));
},
deletePlayer(req, res) {
return Player.findByPk(req.params.id, {
attributes: ['id', 'name', 'nickname', 'profileImg']
})
.then(player => {
if (!player) {
return res.status(404).send({
message: `Player with id ${req.params.id} not found`
});
}
return player
.destroy()
.then(() => res.status(204).send())
.catch(err => res.status(400).send(err));
})
.catch(err => res.status(400).send(err));
}
};
现在,关于几个教程,我应该在console.log(req.file)
使用帖子点击端点时看到其中的信息,对吧?
模型如下所示:
models/player.js(续集模型)
'use strict';
module.exports = (sequelize, DataTypes) => {
const Player = sequelize.define(
'Player',
{
name: {
type: DataTypes.STRING,
validate: { notEmpty: { msg: 'Player name cannot be empty' } }
},
nickname: {
type: DataTypes.STRING
},
profileImg: {
type: DataTypes.STRING
}
},
{}
);
Player.associate = function(models) {
// associations can be defined here
};
return Player;
};
所以现在到前端代码(react.js):
这是我在我的反应应用程序中加载的表单:
playerform.js
import React, { Component } from 'react';
import axios from 'axios';
import {
FormControl,
FormGroup,
FormLabel,
Form,
Button
} from 'react-bootstrap';
import PropTypes from 'prop-types';
class PlayerForm extends Component {
state = {
name: '',
nickname: '',
profileImg: ''
};
handleSubmit = e => {
e.preventDefault();
axios
.post(`${process.env.API_URL}/player`, JSON.stringify(this.state), {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
.then(() => this.props.onCreate())
.catch(err => console.log(err));
};
onFileChange(e) {
this.setState({ profileImg: e.target.files[0] });
}
handelChange = e => {
this.setState({
[e.target.name]: e.target.value
});
};
render() {
return (
<div className="container">
<Form onSubmit={this.handleSubmit}>
<FormGroup>
<FormLabel>Name</FormLabel>
<FormControl
type="text"
name="name"
placeholder="Enter player name"
onChange={this.handelChange.bind(this)}
/>
</FormGroup>
<FormGroup>
<FormLabel>Nickname</FormLabel>
<FormControl
type="text"
name="nickname"
placeholder="Enter player nickname"
onChange={this.handelChange.bind(this)}
/>
</FormGroup>
<FormGroup>
<FormLabel>Picture</FormLabel>
<FormControl
type="file"
name="file"
playerholder="Upload player picture"
onChange={this.onFileChange.bind(this)}
/>
</FormGroup>
<Button variant="btn btn-primary" type="submit">
Add
</Button>
</Form>
</div>
);
}
}
PlayerForm.propTypes = {
onCreate: PropTypes.func.isRequired
};
export default PlayerForm;
因此,当输入内容并点击Add
按钮时,我的 api 声明 req.file 未定义,我无法找出原因。
谁能帮我深入分析错误?
解决方案
multer
您的预期内容与您实际从前端发布的内容略有不同。
如果您使用Postmanmultipart/form-data
(或类似工具),请尝试向您的“创建播放器”端点发送 POST 请求。你可能会看到它有效。
但是,您的 axios 帖子'Content-Type': 'application/json'
以 multer 包无法处理的格式发送数据。
尝试使用new FormData()
此处讨论的构造如何在 axios 中设置多部分并做出反应?
推荐阅读
- json - 我如何遍历python中的json树
- asp.net-mvc - 在具有 Windows 身份验证的本地 ASP.NET Web 应用中嵌入 Power BI
- c# - FindElements 中的 StaleElementReferenceException(By.TagName(“a”)))
- python - Python - 渲染 Jinja 模板和电子邮件
- javascript - 为什么点击路线时会修改道具?
- javascript - Cheerio 和 CSS 选择器
- javascript - GraphQL 类型与 Mongoose 模式不匹配
- html - html 表 colspan 行跨度 Piet Mondrian
- sql - 如何连接具有 LIKE 条件的表?
- git - 将代码推送到 git 分支时出错