Как средствами JavaScript отправить форму, содержащую текстовые поля и файл, в формате JSON?

Есть форма с двумя текстовыми полями — "Заголовок" и "Описание" — и полем прикрепления файла.
Мне нужно отправить эту форму POST-запросом, предварительно преобразовав в JSON.
Вопрос: как?
Большая часть примеров, которые я находил, описывают, либо как отправить отдельно текст, либо — отдельно файл.

Запросы обрабатывает RestController Spring:
@PostMapping("/my/bookunits")
    public ResponseEntity<ApiResponse> createBookUnit(@CurrentUser UserPrincipal currentUser,
                                                      @Valid @ModelAttribute BookUnitRequest bookUnitRequest) {
        User user = userService.loadUserById(currentUser.getId());
        bookUnitService.createBookUnit(user, bookUnitRequest);
        return new ResponseEntity<>(new ApiResponse(Boolean.TRUE, "processing"), HttpStatus.ACCEPTED);
    }


@Data
public class BookUnitRequest {
    @NotBlank
    private String title;

    @NotBlank
    private String description;

    private MultipartFile bookFile;
}


Я так понял, что у всего содержимого формы Content-type должен быть multipart/form-data, верно?
В Poster пробовал через тип данных form-data в Body, всё принималось.
Можно ли в JSON? Если нет, подскажите, как поправить запрос:
$("#newBookUnitForm").submit(function (e) {
    let authToken = localStorage.getItem("accessToken");
    let url = "http://localhost:8080/api/my/bookunits";
    console.log("Попытка загрузить новую книгу на: " + url);

    let newBookUnitRequest = {
        "title": document.getElementById("newBookUnitTitle").value,
        "description": document.getElementById("newBookUnitDescription").value,
        "bookfile": document.getElementById("newBookUnitFile").value
    }
    let newBookUnitRequestJson = JSON.stringify(newBookUnitRequest);

    let xhr = new XMLHttpRequest();
    xhr.open('POST', url, true)
    xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
    xhr.setRequestHeader("Authorization", authToken);
    xhr.onload = function () {
        if (xhr.readyState === 4) {
            switch (xhr.status) {
                case 202:
                    let resp = JSON.parse(xhr.responseText);
                    console.log("Файл принят. Ответ сервера: " + resp.message);
                    break;
                case 401:
                    console.log("Код ответа 401. Ошибка авторизации.");
                    break;
                default:
                    console.log("Код ответа: " + xhr.status + ", ответ сервера: " + xhr.responseText);
            }
        }
    }
    xhr.send(newBookUnitRequestJson);
    e.preventDefault();
})
  • Вопрос задан
  • 261 просмотр
Решения вопроса 1
azerphoenix
@azerphoenix Куратор тега Spring
Java Software Engineer
Я так понял, что у всего содержимого формы Content-type должен быть multipart/form-data, верно?

Да, все верно.

Также не забывайте отправлять csrf токен, если в настройках безопасности он у вас включен. Некоторые шаблонизаторы (например, thymeleaf) делают это автоматически, но при отправке содержимого формы средствами js надо csrf тоже отправлять. Для этого в head добавляется мета-тег, в который вставляется csrf токен.
Затем средствами js необходимо получить значение этого тега (токен) и отправить с формой.
Подробности тут:
https://www.baeldung.com/spring-security-csrf
Раздел 3.4 Using Json - https://www.baeldung.com/spring-security-csrf#4-us...

e.preventDefault();
Скорее всего эта строка должна быть выше всех. Как бы вы сперва останавливаете form submission, а затем уже делаете все остальное. Иначе у вас форма будет отправлена, а затем выполнится остальной код.

А вот, ответ на ваш вопрос:
https://stackoverflow.com/questions/49845355/sprin...
И в первом ответе и во втором описывается вариант отправки формы средствами js с файлом и с другими данными.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
zkrvndm
@zkrvndm
Архитектор решений
Вы можете ваши файлы преобразовать в base64 текст и уже этот текст отправлять на сервер, внутри JSON вместе с остальными данными. Короче, не вижу проблем.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы