如何将文件/图像从React发送到Node.js服务器

时间:2019-06-21 19:24:51

标签: node.js reactjs express postman

我正在尝试使用multer将来自React的文件/图像发送到node.js服务器。问题是我只能通过Postman发送图像,但是当我在React中尝试发送图像时,我得到了:TypeError:无法读取未定义的属性'path'。我不知道应该以二进制格式发送文件/图像还是使用其他格式。我已经尝试使用reader.readAsDataURL()和reader.readAsBinaryString()了,但是没有用。


const multer = require("multer");

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "./uploads/");
  },
  filename: (req, file, cb) => {
    cb(null, new Date().toISOString() + file.originalname);
  }
});

const fileFilter = (req, file, cb) => {
  if (
    file.mimetype === "image/jpeg" ||
    file.mimetype === "image/png" ||
    file.mimetype === "image/jpg"
  ) {
    cb(null, true);
  }
  cb(null, false);
};

const upload = multer({
  storage: storage,
  limits: { fileSize: 5000000 },
  fileFilter: fileFilter
});

// Create a post
router.post(
  "/",
  upload.single("image"),
  passport.authenticate("jwt", { session: false }),

  (req, res) => {
    const { errors, isValid } = validationPostInput(req.body);
    if (!isValid) {
      return res.status(400).json(errors);
    }
    console.log(req.file);
    const newPost = new Post({
      text: req.body.text,
      theme: req.body.theme,
      name: req.body.name,
      avatar: req.body.avatar,
      image: req.file.path,
      user: req.user.id
    });

    newPost.save().then(post => res.json(post));
  }
);

  // CREATE A POST
export const createPost = (userInput, history) => dispatch => {
  const headers = {
    "Content-Type": "form-data"
  };
  axios
    .post("/post", userInput, headers)
    .then(res => history.push("/post/all"))
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};


   import React, { Component } from "react";
import PropTypes from "prop-types";
// import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { createPost } from "../../actions/postActions";
import "./style.css";

class CreatePost extends Component {
  state = {
    text: "",
    theme: "",
    image: "",
    errors: {}
  };

  componentWillReceiveProps(nextProps) {
    if (nextProps.errors) {
      this.setState({ errors: nextProps.errors });
    }
  }

  onSubmit = e => {
    e.preventDefault();

    const { user } = this.props.auth;

    const newPost = {
      text: this.state.text,
      theme: this.state.theme,
      image: this.state.image,
      name: user.username,
      avatar: user.avatar
    };

    this.props.createPost(newPost);
  };
  onChange = e => this.setState({ [e.target.name]: e.target.value });

  fileSelectHandler = e => {
    const param = e.target.files[0];
    let reader = new FileReader();
    reader.readAsDataURL(param);

    this.setState({
      image: reader.result
    });
    console.log(reader);
  };

  render() {
    const { text, theme, errors } = this.state;

    return (
      <section className="post">
        <form
          onSubmit={this.onSubmit}
          className="post__form"
          action="/post"
          method="POST"
          encType="multipart/form-data"
        >
          <div className="post__form--input">
            <label>Theme</label>
            <input
              type="text"
              name="theme"
              value={theme}
              onChange={this.onChange}
            />
            {errors && <small>{errors.theme}</small>}
          </div>
          <div className="post__form--input">
            <label>Text</label>
            <textarea
              type="text"
              name="text"
              value={text}
              onChange={this.onChange}
            />
            {errors && <small>{errors.text}</small>}
          </div>
          <div className="post__form--file">
            <label>Add Image</label>
            <input
              type="file"
              name="file"
              accept=".png, .jpg"
              onChange={this.fileSelectHandler}
            />
          </div>
          <button type="submit" className="button">
            Submit
          </button>
        </form>
      </section>
    );
  }
}

CreatePost.propTypes = {
  errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  errors: state.errors,
  auth: state.auth
});

export default connect(
  mapStateToProps,
  { createPost }
)(CreatePost);

2 个答案:

答案 0 :(得分:1)

最后,我找到了解决该问题的方法。

 onSubmit = e => {
    e.preventDefault();

    const { user } = this.props.auth;

    const form = new FormData();
    form.append("file", this.state.file);
    form.append("theme", this.state.theme);
    form.append("text", this.state.text);
    form.append("name", user.username);
    form.append("avatar", user.avatar);

    this.props.createPost(form);
  }

答案 1 :(得分:0)

您将字段名称发送为file

<input
    type="file"
    name="file"
    accept=".png, .jpg"
    onChange={this.fileSelectHandler}
/>

但是您将在multer上将字段名称设置为"image"

upload.single("image")

您需要将其更改为:

upload.single("file")

正确的syntax是:

.single(fieldname)
     

接受名称为fieldname的单个文件。单个文件将是   存储在req.file中。