Пошаговые инструкции Для начинающих 12 мин

Как принять файл через Webhook в n8n

Отправьте TXT и номер заявки через multipart/form-data: проверка файла, чтение текста и JSON-ответ. 10 шагов, готовый workflow и проверенная команда curl.

n8n webhook Файлы

Отправим в n8n настоящий текстовый файл и номер заявки одним POST-запросом. Webhook примет multipart/form-data, проверка отсеет неподходящий ввод, Extract from File прочитает текст, а клиент получит JSON. Готовую схему и файл можно скачать и повторить локально.

Результат инструкции

На выходе будет ответ с request_id: demo-001, именем note-demo.txt, размером исходного файла в байтах и его текстом. Файл не отправляется в нейросеть, клиенту или рабочую базу. Значение action: false обозначает учебный просмотр, а не согласование заявки или запуск бизнес-действия.

Работаем только с вымышленным TXT на локальном Test URL. Workflow неактивен и не предназначен для публикации без доработок. Он принимает ровно один файл с фиксированным именем, а не любые документы. PDF, картинки, OCR, антивирусная проверка и хранение вложений здесь не реализованы.

Что понадобится

  • Локальный n8n и отдельный новый workflow. Проверено на n8n 2.42.4: Webhook 2.1, Code 2, Extract from File 1.1, Respond to Webhook 1.4.
  • Windows PowerShell с curl.exe. В примерах n8n открыт на http://localhost:5679; если у вас другой порт, замените адрес.
  • Скачиваемые JSON-схема и note-demo.txt из этой статьи. Платная подписка, API-ключи и реальные документы не нужны.

Установить n8n локально через Docker

Шаг 1. Скачайте схему и учебный файл

Скачать n8n-webhook-file-upload.json

Скачать note-demo.txt

Сохраните оба файла в отдельную папку. Если браузер просто показывает текст, сохраните его как note-demo.txt, без дополнительного расширения .txt.txt. Для точного повторения лучше использовать скачанный оригинал: в нём UTF-8 без BOM и переводы строк LF, размер 63 байта.

text
Заявка: demo-001
Нужен учебный расчёт.

В оригинальном файле после второй строки тоже есть перевод строки. Ручной ввод в редакторе может дать другой размер из-за CRLF или BOM. Это не обязательно ошибка: схема считает реальные байты и поддерживает эти варианты, но основной ожидаемый ответ ниже относится к скачанному файлу.

Шаг 2. Импортируйте отдельный workflow

Создайте новый workflow, используйте Import from File и выберите n8n-webhook-file-upload.json. Должны появиться пять соединённых узлов:

text
Upload Request → Check Upload → Read Text → Upload Preview → Send Reply

Upload Request — Webhook, Check Upload и Upload Preview — Code, Read Text — Extract from File, Send Reply — Respond to Webhook. Сохраните схему, но не публикуйте её. Не переносите узлы в действующий workflow, пока не получите учебный ответ.

Шаг 3. Настройте Webhook на multipart-запрос

Поле Webhook Значение Зачем
HTTP Method POST Команда curl отправит форму
Path ezgpt-file-upload Путь учебного endpoint
Authentication None, только локальный тест Не открывать такой endpoint в сеть
Respond Using Respond to Webhook node Ответ вернёт Send Reply

В Options оставьте настройки по умолчанию. Для этой схемы не включайте Raw Body и Binary Property и не задавайте переименование binary-поля. multipart/form-data разбирается на текстовые поля и файлы: request_id будет в $json.body, а файл из поля формы document — в binary.document.

Это не отправка всего тела запроса как одного бинарного потока. Настройки для raw binary нельзя механически переносить на multipart: иначе последующие узлы увидят другую структуру. В импортированной схеме уже выставлен нужный вариант.

Шаг 4. Проверьте файл и номер заявки

В Check Upload выберите Run Once for All Items и JavaScript. Код уже есть в JSON-схеме; при ручной сборке вставьте его целиком:

javascript
Показать код (33 строк)
const items = $input.all();
if (items.length !== 1) throw new Error('Expected one request');
const item = items[0];
const body = item.json.body;
if (!body || typeof body !== 'object' || Array.isArray(body) ||
    Object.keys(body).length !== 1 ||
    typeof body.request_id !== 'string' ||
    !/^demo-[0-9]{3}$/.test(body.request_id)) {
  throw new Error('Expected only request_id: demo-001');
}
const fields = Object.keys(item.binary ?? {});
if (fields.length !== 1 || fields[0] !== 'document') {
  throw new Error('Expected exactly one file in document');
}
const file = item.binary.document;
if (file.fileName !== 'note-demo.txt' || file.mimeType !== 'text/plain') {
  throw new Error('Expected note-demo.txt with text/plain');
}
const buffer = await this.helpers.getBinaryDataBuffer(0, 'document');
if (buffer.length === 0 || buffer.length > 4096) {
  throw new Error('File must contain 1-4096 bytes');
}
const text = buffer.toString('utf8');
if (!Buffer.from(text, 'utf8').equals(buffer)) {
  throw new Error('File must be valid UTF-8');
}
if (!text.replace(/^\uFEFF/, '').trim() || text.includes('\u0000')) {
  throw new Error('Expected nonempty text without NUL');
}
return [{
  json: { request_id: body.request_id, file_name: 'note-demo.txt', bytes: buffer.length },
  binary: { document: file },
}];

Разрешено только поле request_id вида demo-001 и один файл в document. Проверяется фиксированное имя note-demo.txt, заявленный тип text/plain, размер от 1 до 4096 байт, корректный UTF-8, непустой текст и отсутствие NUL. Два файла в одном поле тоже не пройдут: в проверенной версии n8n создаёт document0 и document1, а схема ждёт только document.

getBinaryDataBuffer читает настоящие байты, в том числе когда n8n хранит binary на диске. Не пытайтесь читать файл через item.binary.document.data как обычную строку: там может быть служебная ссылка. После проверки код пропускает только нужные поля, без входящих headers, query и cookies.

Имя и MIME передаёт отправитель, поэтому их совпадение не доказывает безопасность файла. Проверка 4096 байт выполняется уже внутри workflow, после получения загрузки. Это не лимит входящего трафика и не защита сервера от больших запросов.

Шаг 5. Прочитайте TXT через Extract from File

Откройте Read Text. Выберите Operation: Extract From Text File, Input Binary Field: document, Destination Output Field: text. В Options выставьте File Encoding: utf8, Strip BOM: включено, Keep Source: JSON. Это соответствует operation: text в скачиваемой схеме.

Keep Source сохраняет request_id, file_name и bytes из проверки, а текст появится в отдельном поле text. Оригинальный binary далее не нужен. Если оставить только Binary вместо JSON, потеряется номер заявки; если указать data вместо document, узел не найдёт файл.

Узел читает текст, но не выполняет его и не разбирает как JSON. BOM в начале UTF-8 удаляется из результата; bytes остаётся размером исходного файла с BOM. Переводы строк LF или CRLF сохраняются.

Шаг 6. Подготовьте ограниченный JSON-ответ

В Upload Preview выберите Run Once for All Items, JavaScript и проверьте код:

javascript
const item = $input.first();
const { request_id, file_name, bytes, text } = item.json;
if (typeof text !== 'string' || !text.trim() || text.charCodeAt(0) === 0xFEFF) {
  throw new Error('Check Extract from File: text field and Strip BOM');
}
if (!/^demo-[0-9]{3}$/.test(request_id ?? '') ||
    file_name !== 'note-demo.txt' || !Number.isInteger(bytes)) {
  throw new Error('Check Keep Source: JSON');
}
return [{ json: { status: 'preview', request_id, file_name, bytes, text, action: false } }];

Этот узел проверяет, что после извлечения сохранились метаданные и непустое поле text, затем собирает ответ только из известных полей. Не заменяйте его возвратом всего входа Webhook. Для примера возвращаем текст собственного небольшого файла; для реальных договоров и персональных данных такое отражение содержимого может быть недопустимо.

В Send Reply задайте Respond With: First Incoming Item и Response Code: 200. В Response Headers добавьте Cache-Control: no-store. Во всех рабочих узлах оставьте On Error: Stop Workflow, без Continue On Fail и без Always Output Data. Иначе ошибка проверки может попасть в ветку успешного ответа.

Шаг 7. Включите ожидание Test URL

Откройте Upload Request, выберите Test URL и нажмите Listen for test event или Execute workflow. Скопируйте фактический URL своего экземпляра. Ниже используется http://localhost:5679/webhook-test/ezgpt-file-upload.

Пока слушатель не запущен, Test URL не работает. В проверенном режиме он принимает один успешный запрос, после чего перед следующим тестом нужно снова включить ожидание. Production URL у неопубликованной схемы не зарегистрирован. Открытие ссылки в адресной строке отправляет GET, а здесь нужен POST.

Шаг 8. Отправьте файл и поле формы

Откройте папку со скачанным note-demo.txt в Проводнике и запустите в ней PowerShell. Проверьте наличие файла:

powershell
Get-Item -LiteralPath .\note-demo.txt | Select-Object Name, Length

Должны быть имя note-demo.txt и Length 63 для оригинала. Затем выполните одну строку, заменив адрес при необходимости:

powershell
curl.exe --include --max-time 15 --form "request_id=demo-001" --form "document=@note-demo.txt;type=text/plain" "http://localhost:5679/webhook-test/ezgpt-file-upload"

Символ @ заставляет curl читать содержимое файла. Без него отправится строка с именем, а не файл. Не добавляйте вручную Content-Type: multipart/form-data: curl сам создаёт границу частей boundary и правильный заголовок. В Windows используйте именно curl.exe, а не неоднозначный псевдоним curl.

Флаг --include выводит HTTP-заголовки перед JSON. Если curl пишет, что не может прочитать файл, запрос ещё не отправлен: проверьте текущую папку и расширение. Не исправляйте это подстановкой реального рабочего документа.

Шаг 9. Сверьте ответ и выполнение

Ожидайте HTTP 200, заголовок Cache-Control: no-store и следующий JSON для скачанного оригинала:

json
{
  "status": "preview",
  "request_id": "demo-001",
  "file_name": "note-demo.txt",
  "bytes": 63,
  "text": "Заявка: demo-001\nНужен учебный расчёт.\n",
  "action": false
}

request_id должен совпасть с полем формы, text — с текстом файла, bytes — с его размером. Кириллица должна читаться нормально. Экранированные Unicode-последовательности в JSON могут быть допустимым представлением текста; сломанные символы и неверный текст — нет.

Где проверить Ожидается Что это доказывает
Upload Request body.request_id и Binary: document Пришёл multipart, а не строка имени
Check Upload request_id, file_name, bytes Проверки пройдены
Read Text text и исходные JSON-поля Файл прочитан, метаданные сохранены
Send Reply 200 и ограниченный JSON Клиент получил нужный результат

Не считайте зелёный Webhook достаточным результатом: весь путь должен закончиться Send Reply. История n8n может сохранять текст, метаданные и binary входящего запроса. Даже при отсутствии записи в вашу бизнес-базу это не означает, что файл нигде не хранится. Для реальных данных нужны отдельные правила доступа и удаления executions.

Шаг 10. Проверьте отказ без файла

Снова включите ожидание Test URL и отправьте запрос только с номером заявки:

powershell
curl.exe --include --max-time 15 --form "request_id=demo-001" "http://localhost:5679/webhook-test/ezgpt-file-upload"

В проверенном n8n 2.42.4 эта учебная схема вернула HTTP 500: Check Upload остановился с Expected exactly one file in document, Send Reply не запустился. Подробность смотрите в ошибке execution, а не ожидайте её обязательно в теле ответа curl. Это преднамеренно простой сценарий остановки, не готовый обработчик клиентских ошибок с 400 или 422.

Для дополнительной проверки замените имя поля document в успешной команде на file, снова включите ожидание и повторите. Файл не должен пройти проверку. Затем верните исходную команду и убедитесь, что успешный результат повторяется.

Если результат отличается

Симптом Вероятная причина Что исправить
404 Нет слушателя, неверный метод или URL Включить Test URL и отправить POST
curl не читает файл Другая папка или двойное расширение Проверить Get-Item и путь после @
500 в Check Upload Нет document, лишние поля или неподходящий файл Сверить форму и ограничение 4096 байт
Read Text не видит binary Указано data вместо document Исправить Input Binary Field
500 в Upload Preview Потеряны text или метаданные Сверить Destination и Keep Source: JSON

Что изменить перед реальным использованием

Не публикуйте этот workflow с Authentication None. Для сетевого доступа нужны HTTPS, проверка доступа, лимиты размера на входе и частоты запросов, сроки хранения загрузок и истории. Используйте согласованный контракт полей, а не случайное имя файла клиента как путь на сервере.

Настроить Header Auth для Webhook

Если нужен ответ 400 или 422 на неподходящий файл, сначала спроектируйте отдельную ветку проверки и Respond to Webhook для отказа. В этой схеме исключение останавливает выполнение с 500. Для PDF потребуется другой обработчик; отсканированные страницы могут требовать OCR. Проверка UTF-8 не заменяет антивирус, проверку формата и ручное согласование дальнейших действий.

Обратная задача: вернуть файл из Webhook

Что проверено редакцией

17 октября 2026 года публичная JSON-схема проверена реальными multipart-запросами в отдельном локальном Docker-экземпляре n8n 2.42.4 с binary на диске. Все 26 проверок прошли. Точный ответ 200 получен для исходного UTF-8 TXT, CRLF, UTF-8 BOM и многоязычного текста; команда curl.exe проверена отдельно. Подтверждены отказы 500 без файла, с другим полем, двумя файлами, неверным именем или MIME, отсутствующим или неверным request_id, лишним полем, пустым или пробельным файлом, размером 4097 байт, неверным UTF-8, NUL, JSON вместо multipart и тремя ошибками настройки Extract from File. При отказах Send Reply не запускался. Проверены 404 без слушателя, при GET вместо POST, повторе после успешного теста и у неактивного Production URL. Настройки сверены с официальной документацией и кодом Webhook и Extract from File из этой версии. Контейнер был привязан только к loopback и остановлен; существующие workflows не менялись. Клики редактора, загрузка через браузерную форму, n8n Cloud, production, reverse proxy, OCR и проверка файлов на вредоносность не тестировались. Обложка — редакционная AI-иллюстрация, не снимок интерфейса.

Частые вопросы

Почему имени файла в JSON недостаточно?

Строка note-demo.txt не содержит байты файла. Для этой схемы нужен multipart-запрос с файловым полем document; в curl файл передаётся через @.

Нужно включить Binary Property или Raw Body?

Нет, не для описанной multipart-схемы. Оставьте Options Webhook по умолчанию: файл формы document попадёт в binary.document. Raw binary — другой способ передачи.

Можно отправить PDF или картинку?

Нет. Учебный пример принимает только note-demo.txt с текстом UTF-8. Для PDF, изображений и OCR нужны другие операции и проверки.

Почему размер отличается от 63 байт?

63 байта относится к скачанному оригиналу. CRLF вместо LF даст 65, UTF-8 BOM с исходными LF — 66. Схема считает исходные байты, а BOM убирает только из извлечённого текста.

Можно сразу открыть endpoint для клиентов?

Нет. Нужны авторизация, HTTPS, входные лимиты, управление хранением и отдельные ответы на ошибки. None и HTTP здесь используются только для собственного локального теста.

Дальше по теме

Похожие материалы