У меня есть REST API, созданный с использованием AWS Lambdas и шлюза API.
Этот API поддерживает загрузку файлов, и у меня есть требование анализировать загруженные файлы, а затем отправлять эти файлы по отдельности в другой источник в виде данных формы.
Когда я отправляю два изображения через почтальона и регистрирую тело события, я получаю следующую строку. (У него два файла)
----------------------------269453880547064499146449
Content-Disposition: form-data; name = "file"; filename = "smiling.png"
Content-Type: image/png
�PNG
IHDR��asBIT|d�^IDAT8���=KBa��IB����"�-P\�6!Bz�D�c�hk�K�hAV`Km���K�PKm��Oý�R�-�O��<�#ZkzT���4B��nMȑ0����@#�A�- ����7w��"�fY��J�C�)�Z`D3�a��E�h���<F�7w����d�ɉ7���Y�?f�+Y�&9�B����P����`%�d:�T
�m�h�K�`����zT;�e �mc�$=A�q���&@Y��4O=W����P@�T���*��V�t`a��H�UD��6��Һ���W[��, ��u�Ea�.c�-��S�z���Q�`���S�~y��xݡ�O�]IEND�B`�
----------------------------269453880547064499146449
Content-Disposition: form-data; name = "file"; filename = "smiling.png"
Content-Type: image/png
�PNG
IHDR��asBIT|d�^IDAT8���=KBa��IB����"�-P\�6!Bz�D�c�hk�K�hAV`Km���K�PKm��Oý�R�-�O��<�#ZkzT���4B��nMȑ0����@#�A�- ����7w��"�fY��J�C�)�Z`D3�a��E�h���<F�7w����d�ɉ7���Y�?f�+Y�&9�B����P����`%�d:�T
�m�h�K�`����zT;�e �mc�$=A�q���&@Y��4O=W����P@�T���*��V�t`a��H�UD��6��Һ���W[��, ��u�Ea�.c�-��S�z���Q�`���S�~y��xݡ�O�]IEND�B`�
----------------------------269453880547064499146449--
Я использовал lambda-multipart-parser для разбора этого тела и извлечения метаданных.
import parser from 'lambda-multipart-parser'
....
const result = await parser.parse(event)
Результат выше дает файлы со следующим типом.
{
filename: string
content: Buffer
contentType: string
encoding: string
fieldname: string
}
У меня проблема в том, что я должен отправлять эти файлы по отдельности на другой сервер как multipart/formdata.
Подходы, которые я пробовал до сих пор.
Подход 1
Использовал регулярное выражение для разделения тела события по границе, границей сети в примере является ----------------------------269453880547064499146449.
const splitFileBody = event.body?.split(fileBoundary)
После разделения у меня осталась строка.
// In this example I am only trying to send one file
formData.append('file', splitFileBody[0])
Результат: описанный выше подход дает мне код состояния 400 HTTP вместе со следующей ошибкой.
тело вашего POST-запроса неправильно сформировано multipart/form-data
Подход 2
Попытался создать объект типа File в лямбда-выражении, используя проанализированный файл следующим образом.
const fileC = new File([file.content], file.fieldname, { type: file.contentType, lastModified: Number(new Date()) })
console.info('fileC', fileC)
const formData = new FormData()
formData.append('file', fileC)
Результат: журналы Lambda выдают ошибку File is not defined.
Подход 3
Передал проанализированную информацию в form.append напрямую без new File
form.append('file', file.content, {
filename: file.filename,
contentType: file.contentType
});
Результат: описанный выше подход дает мне код состояния HTTP 400 вместе со следующей ошибкой.
тело вашего POST-запроса неправильно сформировано multipart/form-data
Верны ли мои подходы. Если нет, что мне делать по-другому. Если подходы выше подходят, то какой из них лучше и как избежать ошибок?
Дополнительная информация
form-data
, потому что я продолжал получать FormData is not defined during the lambda runtime
.import FormData from 'form-data'
....
formData.append('file', file.content, {
filename: file.filename
})
const res = await axios.post(URL, formData, {
headers: {
...formData.getHeaders(),
'content-length': file.content.length
}
})
Содержимое проанализированного файла может быть напрямую добавлено к formData из form-data следующим образом.
const result = await parser.parse(event)
const formData = new FormData();
for (const file of result.files) {
formData.append('file', file.content, {
filename: file.filename,
contentType: file.contentType
});
}
Кроме того, content-length должно иметь значение formData.getLengthSync() следующим образом. Причина в том, что formData может содержать другие добавленные к нему поля, а file.content.length содержит только размер файла, а не другие добавленные данные.
await axios.post(URL, formData, {
headers: {
...formData.getHeaders(),
'Content-Length': formData.getLengthSync()
}
})
Можете ли вы включить код, где вы делаете запрос, т.е. проходите formData
Привет, я обновил дополнительную информацию внизу
Попробуйте обновленный код, попробуйте сделать запрос без заголовков и т. д.
Привет, Трейнор, я отредактировал твой ответ, добавив улучшения и рабочее решение.
Большой. Я думал, что это была часть запроса, вы были на правильном пути, потому что, если бы простой запрос не работал, моей следующей попыткой было бы поиграть с headers, согласно документам: npmjs.com/package/form-data #аксиос
Спасибо за комментарий @traynor. Это дает мне The body of your POST request is not well-formed multipart/form-data. похожее на первый подход. Я обновлю свой вопрос, чтобы включить этот подход.