Как отправить файл/изображение из React на сервер node.js

Я пытаюсь отправить файл/изображение из React на сервер node.js с помощью multer. Проблема в том, что я могу отправить изображение только через Postman, но когда я пытаюсь сделать то же самое в React, я получаю: TypeError: Cannot read property 'path' of undefined. Я не понимаю, следует ли мне отправлять файл/изображение в двоичном формате или использовать другой формат. Я уже пытался использовать 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.info(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.info(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);

эй, вы можете создать прототип здесь, это будет легко для отладки codeandbox.io/s/узел

user10972884 21.06.2019 21:30

мой сервер подключается к mongoDB, я не думаю, что смогу это сделать

Ilya Solodeev 21.06.2019 21:38

может быть, вы можете издеваться над своими данными

user10972884 21.06.2019 21:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
10 505
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы отправляете имя поля как file:

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

Но вы устанавливаете имя поля как "image" на multer:

upload.single("image")

Вам нужно изменить его на:

upload.single("file")

Правильный синтаксис:

.single(fieldname)

Accept a single file with the name fieldname. The single file will be stored in req.file.

Я изменил, но у меня та же проблема. Возможно, проблема в данных, которые я пытаюсь отправить. Мультер какого формата может красный?

Ilya Solodeev 22.06.2019 06:24
Ответ принят как подходящий

Наконец-то я узнал, как решить эту проблему.

 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);
  }

Другие вопросы по теме

Как искать значение в массиве внутри другого массива
Почему useEffect не обновляет значение после вызова API?
Невозможно исправить «Неожиданное имя токена «i», ожидаемый пункт «;»» от UglifyJs
Как зафиксировать новый идентификатор записи, созданной в react-admin?
Запустил «http-сервер» с помощью командной строки, он работает, но не работает
Есть ли способ универсально отменить все вызовы setstate для любого несмонтированного компонента или скрыть ошибки, вызванные попыткой?
React/Styled-Components: необходимо вручную свернуть раскрывающийся список с несколькими версиями, которые разработчик может использовать, передав тип в
Как я могу использовать «оверлей» Openlayer внутри React?
Как правильно указать часовой пояс и формат объекта даты в момент времени, чтобы я не получал предупреждение о недопустимой дате и о том, что момент устарел?
«Отсутствует возвращаемый тип функции» для каждого метода класса React