Лирическое вступление
Чтобы писать посты в блог нужен редактор. Чтобы посты читали в них нужно добавлять картинки. Чтобы добавлять картинки в посты в редакторе должна быть кнопка «Добавить картинку». И она у меня есть, но, как в том анекдоте, есть один нюанс* и состоит он в том, что редактор постов является самописным Vue приложением в основе которого Vue2Editor который, в свою очередь, построен вокруг редактора Quill (говно, не используйте). Как следствие самописности, реализация таких вещей как загрузка картинок начиная от выбора картинки с помощью диалогового окна или драг-н-дропа до отправки её на сервер ложатся на мои плечи.
Самая суть
Итак, у меня есть код, который загружает картинку на сервер.
handleImageAdded: async function(file) {
if (!file) return
const formData = new FormData()
formData.append('image', file)
const headers = new Headers({
'Content-Type': 'multipart/form-data',
user: /* имя пользователя */,
token: /* токен пользователя */
})
try {
const result = await fetch(
'/api/endpoint/for/image',
{
headers,
method: 'POST',
body: formData
}
)
const url = result.data.url
// … код вставки картинки в пост
} catch (error) {
console.error(error)
}
}
Кто понял где тут ошибка, тот молодец и дальше может не читать.
Тем, кто не понял скажу, что источник проблемы в отправляемых заголовках. Точнее в Content-Type. Далее в нескольких предложениях я рефлексирую на тему как я допустил такую ошибку. Если вы не любите воду в блогах, то листайте до подзаголовка «Решение»
Посыпаю голову пеплом
Мой основной язык это JavaScript. В последний раз на PHP много лет назад и, когда, в своём переписывании движка сайта с нуля, я дошёл до необходимости загрузить файл на сервер. Я естественно вбил в гугл «PHP загрузка файлов». Первая же ссылка привела меня сюда. Если взглянуть на форму из Примера №1, то можно увидеть, что в тэге <form> указаны несколько свойств. Если они указаны в самом первом примере, рассудил я, который, по идее, должен быть самым простым и минимально рабочим, значит надо их явно передавать. Тем более там первой строчкой идёт комментарий с КАПСЛОКОМ где выделены слова ДОЛЖЕН БЫТЬ. Логично? Логично! А вот и нет!
Решение
Проблема в заголовке Content-Type. Он есть. Он правильный, но с ним что-то не так. Что?
Не так с ним то, что он не полон. Если не устанавливать его в коде, то браузер выставит его самостоятельно и выглядеть он будет вот так:
То есть, даже если мы программно выгружаем файл, то умница-браузер всё равно сам подставит правильный заголовок за нас. Как говаривали на Руси: —«Не лезь вперёд батьки в пекло!». Очень мудрые слова.
Итого есть два стула: на одном вам придётся руками ставить Content-Type и boundary. Это сложно, долго и бессмысленно. На втором вам просто нужно не добавлять заголовок в коде. Выбор за вами.
К столь простому решению меня привёл вот этот комментарий
______
* Если вы не знаете этого анекдота и вы не являетесь тургеневской барышней или HR который по этому посту пытается оценить меня как возможного кандидата, то обязательно загуглите этот анекдот. Если вы HR и рассматриваете меня как возможного кандидата, то не делайте этого.