При интеграции систем часто возникает ситуация, когда необходимо передать большой объем данных в формате JSON через HTTP-сервис. Начинающие разработчики часто сталкиваются с ошибкой HTTP Error 414. The request URL is too long. В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем типичные ошибки при попытке её решения и составим правильный алгоритм отправки данных.
Ошибка 414 означает, что строка запроса (URL) слишком длинная для того, чтобы веб-сервер мог её обработать. Рассмотрим ситуацию: когда мы используем метод GET или передаем данные через параметры в URL (все, что идет после знака вопроса ?), веб-серверы (такие как IIS или Apache) накладывают жесткие лимиты на длину этой строки. Обычно это ограничение составляет от 2048 до 8192 символов. JSON-строка с данными документа или списком товаров легко может превысить этот предел.
Важный вывод: никогда не передавайте JSON-данные через параметры URL. Для передачи структурированных данных большого объема необходимо использовать тело запроса (метод POST или PATCH).
Рассмотрим ситуацию, с которой столкнулся автор темы. Попытка перевести код на использование тела запроса часто сопровождается следующими заблуждениями:
УстановитьТелоИзСтроки. Проанализируем код:
тHTTPЗапрос.УстановитьТелоИзСтроки("Doc_main_data="+вхДанныеДляОтправки.ОсновныеДанныеДокументаJSON);
тHTTPЗапрос.УстановитьТелоИзСтроки("&ECC_Obligations_List="+вхДанныеДляОтправки.СписокЭКРОбязJSON);
УстановитьТелоИзСтроки полностью перезаписывает содержимое тела запроса. В итоге на сервер уйдет только последний фрагмент данных.
Content-Type. При использовании application/x-www-form-urlencoded данные должны быть закодированы специальным образом (URL-encoding). Если просто вставить JSON, содержащий кавычки, пробелы и фигурные скобки, сервер может не понять структуру данных.Запрос.ПараметрыЗапроса. Попытка вызвать Запрос.ПараметрыЗапроса.Получить("Doc_main_data") вернет Неопределено.Выясним, как правильно сформировать запрос на стороне клиента. Лучшей практикой является использование типа контента application/json. В этом случае мы не придумываем имена переменных в строке, а отправляем «чистый» JSON-объект.
Рассмотрим пошагово реализацию на стороне отправителя:
// 1. Создаем структуру данных, которую хотим отправить
ДанныеДляОтправки = Новый Структура;
ДанныеДляОтправки.Вставить("ОсновныеДанные", вхДанныеДляОтправки.ОсновныеДанныеДокументаJSON);
ДанныеДляОтправки.Вставить("СписокОбязательств", вхДанныеДляОтправки.СписокЭКРОбязJSON);
// 2. Сериализуем структуру в одну общую JSON-строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ДанныеДляОтправки);
СтрокаJSON = ЗаписьJSON.Закрыть();
// 3. Формируем соединение и запрос
тСоединение = Новый HTTPСоединение("myfoods.kz", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
тHTTPЗапрос = Новый HTTPЗапрос("/BIS/hs/InDocSinh");
// 4. Устанавливаем заголовок Content-Type
тHTTPЗапрос.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// 5. Устанавливаем тело запроса ОДНИМ вызовом
// Важно: ByteOrderMark.НеИспользовать критичен для многих парсеров
тHTTPЗапрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// 6. Отправляем запрос
тHTTPОтвет = тСоединение.ОтправитьДляОбработки(тHTTPЗапрос);
Теперь разберем, как принять эти данные. Поскольку мы отправили данные в теле запроса методом POST, нам нужно извлечь их из потока тела.
Посмотрим на пример кода внутри метода HTTP-сервиса:
Функция InDocSinhPost(Запрос)
// Получаем тело запроса как строку
СтрокаJSON = Запрос.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
Если ПустаяСтрока(СтрокаJSON) Тогда
Возврат Новый HTTPСервисОтвет(400); // Bad Request
КонецЕсли;
// Десериализуем JSON
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Данные = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
// Теперь данные доступны как свойства структуры
ОсновныеДанные = Данные.ОсновныеДанные;
СписокОбязательств = Данные.СписокОбязательств;
// ... логика обработки данных ...
Возврат Новый HTTPСервисОтвет(200);
КонецФункции
Если ваша JSON-строка занимает десятки или сотни мегабайт, хранение её целиком в оперативной памяти в виде переменной Строка может привести к ошибке нехватки памяти (Out of Memory). В этом случае проанализируем возможность работы через файлы.
На стороне отправителя: вместо УстановитьТелоИзСтроки используем УстановитьТелоИзФайла. 1С будет передавать данные в поток постепенно, не загружая их целиком в ОЗУ.
ИмяФайлаТела = ПолучитьИмяВременногоФайла("json");
// ... код записи данных в файл через ЗаписьJSON ...
тHTTPЗапрос.УстановитьТелоИзФайла(ИмяФайлаТела);
На стороне получателя: вместо ПолучитьТелоКакСтроку() используйте метод Запрос.ПолучитьТелоКакПоток(). Это позволит обрабатывать данные «на лету» через ЧтениеJSON.ОткрытьПоток(Поток).
Если даже при использовании POST вы получаете ошибку 413 (Request Entity Too Large), это означает, что сработало ограничение веб-сервера на размер тела сообщения.
maxAllowedContentLength (в файле web.config).LimitRequestBody.Таким образом, для успешной передачи длинных JSON-строк необходимо: использовать метод POST, передавать данные в теле запроса (желательно с типом application/json), избегать многократной перезаписи тела и корректно извлекать данные на сервере через чтение тела, а не через параметры запроса.