I.Y*_*I.Y 5 javascript multipartform-data file form-data node.js
我有一个包含 Redux 和 AXIOS 的完整 MERN 堆栈项目。我使用 FormData 将图像上传到我的带有 multer 的节点服务器,它在我的本地主机上工作得很好,即使我的 chrome 控制台说空?(FormData\xc2\xa0{})。部署后,我的 FormData 为空。因此,我在没有文件的情况下测试了 FormData(只是表单的输入值),并将其传递到服务器并将其放在 req.body 上。
\n\n我尝试添加配置我的 formData 但没有成功。
\n\n我究竟做错了什么???
\n\n例如
\n\nconfig: { headers: { \'Content-Type\': \'multipart/form-data\' } }ETC.....
这是我的一些代码:
\n\n反应 JS 表单
\n\nimport React, { Component, Fragment } from "react";\nimport PropTypes from "prop-types";\nimport { connect } from "react-redux";\nimport TextAreaFieldGroup from "../common/TextAreaFieldGroup";\nimport InputGroup from "../common/InputGroup";\nimport { addEventful, upload } from "../../actions/eventfulActions";\n\nimport Dropzone from "react-dropzone";\n\nconst imageMaxSize = 10000000\n; //bytes\nconst acceptedFileTypes =\n "image/x-png, image/png, image/jpg, image/jpeg, image/gif";\nconst acceptedFileTypesArray = acceptedFileTypes.split(",").map(item => {\n return item.trim();\n});\n\nclass EventfulForm extends Component {\n constructor(props) {\n super(props);\n this.state = {\n eventtitle: "",\n description: "",\n // comments:\'\',\n files: [],\n errors: {}\n };\n\n this.onChange = this.onChange.bind(this);\n this.onSubmit = this.onSubmit.bind(this);\n }\n\n\n componentWillReceiveProps(newProps) {\n if (newProps.errors) {\n this.setState({ errors: newProps.errors });\n }\n }\n\n verifyFile(files){\n if(files && files.length > 0){\n const currentFile = files[0]\n const currentFileType = currentFile.type\n const currentFileSize = currentFile.size\n if(currentFileSize > imageMaxSize){\n alert("TOO MANY FILES")\n return false\n }\n if (!acceptedFileTypesArray.includes(currentFileType)) {\n alert("IMAGES ONLY")\n return false\n }\n return true\n\n }\n }\n onSubmit(e) {\n e.preventDefault();\n const { user } = this.props.auth;\n\n\n\n const formdata = new FormData();\n this.state.files.forEach((file, i) => {\n const newFile = { uri: file, type: "image/jpg" };\n formdata.append("file", file, file.name);\n });\n\n // const newEventful = {\n // eventtitle: this.state.eventtitle,\n // description: this.state.description,\n // pictures: this.state.pictures,\n // name: user.name\n // };\n\n formdata.append("eventtitle", this.state.eventtitle);\n formdata.append("description", this.state.description);\n formdata.append("name", user.name);\n\n this.props.addEventful(formdata);\n this.setState({ eventtitle: "" });\n this.setState({ description: "" });\n this.setState({ files: [] });\n }\n onChange(e) {\n this.setState({ [e.target.name]: e.target.value });\n }\n\n onDrop = (files, rejectedFiles) => {\n if(rejectedFiles && rejectedFiles.length > 0){\n console.log(rejectedFiles)\n this.verifyFile(rejectedFiles)\n }\n if (files && files.length > 0) {\n const isVerified = this.verifyFile(files)\n if(isVerified){\n console.log(files[0].name);\n const formdata = new FormData();\n files.map(file => {\n formdata.append("file", file, file.name);\n });\n // formdata.append("file", files[0], files[0].name);\n\n console.log(formdata);\n // this.props.upload(formdata);\n this.setState({\n files: files\n });\n }\n }\n };\n\n render() {\n const previewStyle = {\n display: "inline",\n width: 100,\n height: 100\n };\n const { errors, files } = this.state;\n\n return (\n <div className="post-form mb-3">\n <div className="card card-info">\n <div className="card-header bg-info text-white">Create an Event</div>\n <div className="card-body">\n <form onSubmit={this.onSubmit}>\n <div className="form-group">\n <InputGroup\n placeholder="Create a event title"\n name="eventtitle"\n value={this.state.eventtitle}\n onChange={this.onChange}\n error={errors.eventtitle}\n />\n {files.length > 0 && (\n <Fragment>\n <h3>Files name</h3>\n {files.map((picture, i) => (\n <p key={i}>{picture.name}</p>\n ))}\n </Fragment>\n )}\n <Dropzone\n onDrop={this.onDrop.bind(this)}\n accept={acceptedFileTypes}\n maxSize={imageMaxSize}\n >\n <div>\n drop images here, or click to select images to upload.\n </div>\n </Dropzone>\n\n\n <TextAreaFieldGroup\n placeholder="Description"\n name="description"\n value={this.state.description}\n onChange={this.onChange}\n error={errors.description}\n />\n </div>\n <button type="submit" className="btn btn-dark">\n Submit\n </button>\n </form>\n </div>\n </div>\n </div>\n );\n }\n}\n\nEventfulForm.propTypes = {\n addEventful: PropTypes.func.isRequired,\n auth: PropTypes.object.isRequired,\n errors: PropTypes.object.isRequired\n};\nconst mapStateToProps = state => ({\n auth: state.auth,\n errors: state.errors,\n eventful: state.files\n});\n\nexport default connect(\n mapStateToProps,\n { addEventful, upload }\n)(EventfulForm);\nRun Code Online (Sandbox Code Playgroud)\n\n我的 FormAction.js
\n\nimport axios from "axios";\n\nimport {\n ADD_EVENTFUL,\n GET_ERRORS,\n ADD_LIKE,\n REMOVE_LIKE,\n GET_EVENTFUL,\n GET_EVENTFULS,\n DELETE_EVENTFUL,\n CLEAR_ERRORS,\n EVENTFUL_LOADING,\n UPLOAD_FILES\n} from "./types";\n\nconst config = {\n onUploadProgress: progressEvent =>\n console.log(\n "Upload Progress" +\n Math.round((progressEvent.loaded / progressEvent.total) * 100) +\n "%"\n )\n};\n// Add eventful\nexport const addEventful = eventfulData => dispatch => {\n dispatch(clearErrors());\n // .post("/api/eventfuls", eventfulData, config)\n\n axios({\n method: \'post\',\n url: \'/api/eventfuls\',\n data: eventfulData,\n config: { headers: { \'Content-Type\': \'multipart/form-data\' } }\n\n }).then(res =>\n dispatch({\n type: ADD_EVENTFUL,\n payload: res.data\n })\n )\n .catch(err =>\n dispatch({\n type: GET_ERRORS,\n payload: err.response.data\n })\n );\n};\nRun Code Online (Sandbox Code Playgroud)\n\n节点.js
\n\nconst express = require("express");\nconst router = express.Router();\nconst mongoose = require("mongoose");\nconst passport = require("passport");\nconst bodyParser = require("body-parser");\n\n// Eventful model\nconst Eventful = require("../../models/Eventful");\nconst User = require("../../models/User");\n\n// Validation\nconst validateEventfulInput = require("../../validation/eventful");\nconst validateCommentInput = require("../../validation/comment");\n\nvar multer = require("multer");\n\nvar fs = require("fs");\nvar path = require("path");\n\nvar btoa = require("btoa");\n\nrouter.use(\n bodyParser.urlencoded({\n extended: false\n })\n);\nrouter.use(bodyParser.json());\n\nvar storage = multer.diskStorage({\n destination: function(req, file, cb) {\n cb(null, __dirname + "../../../uploads"); //you tell where to upload the files,\n },\n filename: function(req, file, cb) {\n cb(null, file.fieldname + "-" + Date.now());\n }\n});\n\nvar upload = multer({\n storage: storage\n}).array("file");\n\nrouter.use((request, response, next) => {\n response.header("Access-Control-Allow-Origin", "*");\n response.header(\n "Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS"\n );\n response.header("Access-Control-Allow-Headers", "Content-Type");\n next();\n});\n\n// @route POST api/eventfuls\n// @desc Create eventful\n// @access Private\nrouter.post(\n "/",\n passport.authenticate("jwt", { session: false }),\n (req, res) => {\n upload(req, res, err => {\n console.log("req.body!!!!!", req.body);\n const { errors, isValid } = validateEventfulInput(req.body);\n\n // Check Validation\n if (!isValid) {\n console.log(errors);\n // If any errors, send 400 with errors object\n return res.status(400).json(errors);\n }\n\n console.log("req.files!!!!!", req.files);\n if (err) {\n console.log(err);\n res.status(404).json({\n uploadFailed: "Upload failed"\n });\n } else {\n let newArr = [];\n\n for (let file of req.files) {\n let fileReadSync = fs.readFileSync(file.path);\n let item = {};\n item.image = {};\n item.image.data = fileReadSync;\n item.image.contentType = "img/png";\n newArr.push(item);\n\n fs.unlink(file.path, function(err) {\n if (err) {\n console.log("error deleting image", file.path);\n } else {\n console.log("deleted image", file.path);\n }\n });\n }\n for (var i = 0; i < newArr.length; i++) {\n var base64 = btoa(\n new Uint8Array(newArr[i].image.data).reduce(\n (data, byte) => data + String.fromCharCode(byte),\n ""\n )\n );\n newArr[i].image.data = base64;\n }\n\n console.log("33333333333333333333", newArr);\n\n const newEventful = new Eventful({\n title: req.body.eventtitle,\n description: req.body.description,\n pictures: newArr,\n user: req.user.id,\n name: req.user.name\n });\n\n newEventful.save().then(eventful => res.json(eventful));\n }\n console.log("skipped....................");\n }\n );\n }\n);\nRun Code Online (Sandbox Code Playgroud)\n\n我的 PM2 上的错误/日志
\n\n\n\n\n0|服务器| 2019-01-13 21:27 -07:00:服务器已准备好接收消息\n 0|服务器 | 2019-01-13 21:28-07:00:请求正文!!!!! [对象:null\n 原型] {} 0|服务器 | 2019-01-13 21:28-07:00:请求文件!!!!!\n [] 0|服务器 | 2019-01-13 21:28 -07:00: { [错误: ENOENT: 没有这样的\n文件或目录,打开 \'/var/www/LCTW/uploads/file-1547440111023\']\n 0|服务器| 2019-01-13 21:28 -07:00: 错误号: -2, 0|服务器 |\n 2019-01-13 21:28 -07:00: 代码: \'ENOENT\', 0|服务器 | 2019-01-13\n 21:28 -07:00: 系统调用: \'open\', 0|server | 2019-01-13 21:28 -07:00:\n 路径: \'/var/www/LCTW/uploads/file-1547440111023\', 0|服务器 |\n 2019-01-13 21:28 -07 :00: 存储错误: [] }
\n
在这里我的 req.body 和 req.files 是空的。\n但是
\n\n当我在 Node.js 上注释掉文件部分时,req.body 存在!
\n\n0|server | 2019-01-13 21:40 -07:00: req.body!!!!! [Object: null prototype] {\n0|server | 2019-01-13 21:40 -07:00: eventtitle: \'asdfas\',\n0|server | 2019-01-13 21:40 -07:00: description: \'asdfads\',\n0|server | 2019-01-13 21:40 -07:00: name: \'In Soo Yang\' }\nRun Code Online (Sandbox Code Playgroud)\n
我可以在你的代码中看到两个问题
首先从body-parser的 npm 页面
由于其复杂且通常较大的性质,这不能处理多部分主体。对于多部分主体,您可能对以下模块感兴趣:
- 巴士男孩和连接巴士男孩
- 多方和连接多方
- 强大
- 穆尔特
所以body-parser不会填充 ,req.body但由于您已经在使用multer这里是一个关于如何使用 . 填充 的req.body示例multipart/form-data。
app.post('/', upload.none(), function (req, res, next) {
// req.body contains the text fields
})
Run Code Online (Sandbox Code Playgroud)
但由于您需要文件而上述内容不起作用,您可以使用upload.any()
其次,您的中间件注入顺序错误。
改变这个
var upload = multer({
storage: storage
}).array("file");
Run Code Online (Sandbox Code Playgroud)
到
var upload = multer({
storage: storage
})
Run Code Online (Sandbox Code Playgroud)
而不是
router.post(
"/",
passport.authenticate("jwt", { session: false }),
(req, res) => {
upload(req, res, err => {
//code
}
);
}
);
Run Code Online (Sandbox Code Playgroud)
做
router.post(
"/",
passport.authenticate("jwt", { session: false }),
upload.array("file"), //or upload.any()
(req, res) => {
//....code
//now req.body sould work
//file should be at req.files
);
}
);
Run Code Online (Sandbox Code Playgroud)
编辑1
添加 app.js 或 index.js 或您应用程序的起点
global.rootPath = __dirname;
Run Code Online (Sandbox Code Playgroud)
global.rootPath现在将拥有您的应用程序的完整路径。前 /usr/user/Desktop/myapp
使用path,join(global.rootPath, "uploads")会给你/usr/user/Desktop/myapp/uploads。使用的好处path.join是它可以处理不同的操作系统路径系统,例如 Windows 和 *nix
始终用于path.join创建所有路径。
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, path.join(global.rootPath, "uploads")); //you tell where to upload the files,
},
filename: function(req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
}
});
Run Code Online (Sandbox Code Playgroud)