При интеграции 1С с внешними сайтами и веб-сервисами разработчики часто сталкиваются со следующей проблемой: при отправке POST-запроса, содержащего JSON-строку, принимающая сторона (сервер) получает искаженные данные, в которых все двойные кавычки оказываются экранированными обратным слэшем (например, \"rateId\":\"0\" вместо нормального "rateId":"0"). В результате бэкенд сайта не может корректно распарсить входящий JSON-пакет и возвращает ошибку или пустой результат.
В этой статье мы подробно разберем физику этого процесса, выясним истинные причины такого поведения веб-серверов и рассмотрим два готовых практических решения проблемы на стороне 1С и принимающего сервера.
В процессе обмена данными по протоколу HTTP ключевую роль играет заголовок Content-Type. Именно он сообщает веб-серверу, в каком формате передаются данные в теле запроса и как их нужно обрабатывать. Ошибка экранирования кавычек возникает на стыке двух разных стандартов:
param1=value1¶m2=value2). Если мы пытаемся передать JSON в виде body={"rateId":"0"} без предварительной подготовки, веб-сервер видит служебные символы URL (кавычки, фигурные скобки, двоеточия). Чтобы обезопасить систему от инъекций и синтаксических ошибок, парсер веб-сервера принудительно экранирует кавычки, превращая их в \".application/json, но принимающий скрипт на сайте настроен на чтение стандартного POST-массива (например, глобальной переменной $_POST в PHP), сервер вернет пустой запрос. Это происходит потому, что при отправке JSON данные пишутся напрямую в тело (payload) запроса, а не в переменные формы. Принимающий скрипт не находит ожидаемую переменную и считает запрос пустым.Рассмотрим детально, как решить эту проблему в зависимости от ваших возможностей по доработке принимающего сервера.
Если веб-сервер разработан сторонними специалистами и жестко требует передачи данных в формате application/x-www-form-urlencoded с параметром body, нам необходимо выполнить правильное URL-кодирование строки JSON на стороне 1С перед ее отправкой.
Для этого в платформе 1С предусмотрена встроенная функция КодироватьСтроку с использованием системного перечисления СпособКодированияСтроки.КодировкаURL. При таком подходе все небезопасные символы (включая кавычки) заменяются их шестнадцатеричными эквивалентами (например, кавычка превратится в %22), а сервер при получении автоматически декодирует их обратно в нормальный JSON.
Разберем этот процесс на примере кода:
// 1. Создаем защищенное HTTP-соединение
Соединение = Новый HTTPСоединение(
"api.mysite.net",
443,
, , , ,
Новый ЗащищенноеСоединениеOpenSSL()
);
// 2. Указываем заголовки для передачи параметров формы
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// 3. Формируем JSON из структуры 1С
ЗаписьJSON = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет, " ", Истина);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("rateId", "0");
СтруктураДанных.Вставить("email", "ray_honda@mail.ru");
СтруктураДанных.Вставить("phone", "+79111111111");
ЗаписатьJSON(ЗаписьJSON, СтруктураДанных);
СтрокаJSON = ЗаписьJSON.Закрыть();
// 4. КРИТИЧЕСКИ ВАЖНО: Кодируем полученную JSON-строку в формат URL
СтрокаJSON_Закодированная = КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.КодировкаURL);
// 5. Формируем тело запроса в виде параметр=значение
ТелоЗапроса = "body=" + СтрокаJSON_Закодированная;
// 6. Отправляем запрос на сервер
Запрос = Новый HTTPЗапрос("/order/create", Заголовки);
Запрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Результат = Соединение.ОтправитьДляОбработки(Запрос);
При использовании этого метода на сервер придет валидный URL-запрос, парсер бэкенда автоматически превратит %22 в обычные двойные кавычки, и JSON прочитается без искажений и лишних слэшей.
Наиболее правильным решением с точки зрения архитектуры веб-сервисов является передача чистого JSON-пакета непосредственно в теле POST-запроса, минуя промежуточные обертки вроде body=.... Для реализации этого сценария нам потребуется скорректировать логику как в 1С, так и на принимающем веб-сервере.
Шаг 1. Настройка отправки из 1С
В коде 1С мы меняем заголовок Content-Type на application/json и передаем чистую строку JSON в метод УстановитьТелоИзСтроки без каких-либо префиксов:
Соединение = Новый HTTPСоединение("api.mysite.net", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
// Устанавливаем заголовок контента JSON
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json;charset=utf-8");
// Формируем JSON-строку
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет));
// (Заполнение структуры аналогично предыдущему примеру)
ЗаписатьJSON(ЗаписьJSON, СтруктураДанных);
СтрокаJSON = ЗаписьJSON.Закрыть();
Запрос = Новый HTTPЗапрос("/order/create", Заголовки);
// Передаем ЧИСТЫЙ JSON в тело запроса.
// Обязательно отключаем BOM (Byte Order Mark), чтобы у сервера не возникло проблем с парсингом
Запрос.УстановитьТелоИзСтроки(СтрокаJSON, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Результат = Соединение.ОтправитьДляОбработки(Запрос);
Шаг 2. Настройка приема на стороне веб-сервера
Поскольку данные больше не приходят в виде переменных формы, стандартные инструменты чтения POST-параметров не сработают. Нам нужно прочитать «сырое» тело HTTP-запроса. Рассмотрим, как это сделать на популярных бэкенд-платформах:
$_POST['body'] используйте чтение из входного потока php://input:
// Читаем сырые данные из тела запроса
$json_raw = file_get_contents('php://input');
// Декодируем строку в ассоциативный массив
$data = json_decode($json_raw, true);
const express = require('express');
const app = express();
// Подключаем парсинг JSON-тела запроса
app.use(express.json());
app.post('/order/create', (req, res) => {
// Данные автоматически доступны в объекте req.body
console.log(req.body.rateId);
});
@RequestBody для автоматической десериализации входящего JSON в Java-объект:
@PostMapping("/order/create")
public ResponseEntity<?> createOrder(@RequestBody OrderDto orderDto) {
// Spring автоматически распарсит JSON из тела запроса в объект orderDto
return ResponseEntity.ok(orderDto);
}
Обратите внимание на третий параметр метода УстановитьТелоИзСтроки в коде 1С: мы явно передаем ИспользованиеByteOrderMark.НеИспользовать.
Если этот параметр опустить, 1С по умолчанию запишет в начало текстового потока невидимые спецсимволы разметки кодировки UTF-8 (BOM). Большинство стандартных парсеров JSON на стороне веб-серверов при обнаружении этих символов в начале строки выдают ошибку разбора и полностью отказываются обрабатывать пакет, из-за чего веб-сервис будет возвращать статус 400 (Bad Request) или сообщать о пустом запросе.
Резюме: Чтобы избавиться от экранирования кавычек, всегда соотносите тип передаваемого контента с заголовками HTTP. Если используете application/x-www-form-urlencoded — обязательно применяйте метод КодироватьСтроку. Если проектируете интеграцию с нуля — отдавайте предпочтение отправке «чистого» JSON с заголовком application/json и отключенным BOM.