Как обмениваться изображениями между React и Spring

Я разрабатываю фулл-стек интернет-магазин и мне нужно с реакта передавать изображение на мой Spring Rest Controller. Как мне это сделать? Я попытался сделать что-то типо того:

setFile(e.target.files && e.target.files[0])

Это файл из <input type="file"/>

После этого я отправляю файл в put-методе

DishesService.addDish(dish, file)
static async addDish(dish: IDish, file: any) {
        try {
            await axios.post<IDish>('http://localhost:8080/dishes', dish)
                .then(response => {
                    this.updateDishImage(response.data.id, file)
                })
        } catch (e) {
            console.log('произошла ошибка при добавлении блюда')
        }
    }

    static async updateDishImage(id: number | undefined, image: any) {
        try {
            await axios.put('http://localhost:8080/dishes/' + id, {}, {
                params: {
                    file: image
                }
            })
        } catch (e) {
            console.log('Произошла ошибка при добавлении картинки к блюду')
        }
    }

И мой put-метод в контроллере Spring:

    @PutMapping("{dishId}")
    public ResponseEntity<DishEntity> updateDishImage(@PathVariable Long dishId, @RequestParam("file") MultipartFile file) {
        DishEntity updateDish = dishService.updateDishImage(file, dishId);

        return ResponseEntity.ok(updateDish);
    }

Я получаю ошибку:

org.springframework.web.multipart.MultipartException: Current request is not a multipart request

Ответы (1 шт):

Автор решения: Михаил Ребров

Насколько я вижу, проблема в том, как вы с фронта подготавливаете и отправляете запрос.

await axios.put('http://localhost:8080/dishes/' + id, {}, {
    params: {
        file: image
    }
})

Content-Type

Начнем с того, что вы не указываете Content-Type запроса.
По умолчанию будет использоваться

Content-Type=application/x-www-form-urlencoded

При этом в контроллере Вы пытаетесь получить MultipartFile file, который подразумевает запрос типа multipart/form-data

Передача данных

Вы передаете данные, через params(параметры запроса).
Это значит что параметры

{
    param1: "value1",
    param2: "value2",
    param3: "value3"
}

будут преобразованы в строку

param1=value1&param2=value2&param3=value3

и будут добавлены в адресную строку

http://localhost:8080/dishes/{id}?param1=value1&param2=value2&param3=value3

и в таком виде запрос уйдёт на сервер.

И это точно не наш вариант!

Для того, чтобы данные дошли до сервера их следует передавать в data

Что нужно делать

  1. Указываем заголовок с корректным Content-Type
  2. Собирваем данные и передаем их через data
await axios({
  method: "put",
  url: 'http://localhost:8080/dishes/' + id,
  // в data передаем объект с данными формы
  data: {  
         file: file,
         // ... при необходимости указываем другие поля формы
  },
  headers: { "Content-Type": "multipart/form-data" }, // указываем Content-Type
});
→ Ссылка