Кодирование данных

При отправке REST-запросов специальные символы в параметрах могут нарушить структуру URL. Это приведет к ошибкам или неверным данным.

Например, нужно создать лид с названием John&Martin через входящий вебхук. Согласно документации метода crm.lead.add, URL запроса должен выглядеть так:

https://b24-abcdef.bitrix24.ru/rest/1/xxxxxxx/crm.lead.add?fields[TITLE]=John&Martin
        

После выполнения запроса можно обнаружить, что в названии лида осталось только John. Это произошло из-за того, что символ & разделяет параметры запроса. Если он встречается внутри значения, сервер воспримет его как начало нового параметра, а не как часть данных.

Поэтому у запроса образовалось два параметра:

  • fields[TITLE] со значением John
  • новый параметр Martin без значения

Для корректной работы метода нужно заменить специальный символ на кодированный аналог. Для & это %26. Такое преобразование называется URL-кодированием.

Правильный URL для поставленной задачи:

https://b24-abcdef.bitrix24.ru/rest/1/xxxxxxx/crm.lead.add?fields[TITLE]=John%26Martin
        

Какие символы нужно кодировать

В URL особую роль играют: &, ?, %, [, ], # и другие. Если они встречаются в значении параметра, их обязательно кодируют. Иначе сервер интерпретирует их как служебные, и результат запроса станет непредсказуемым.

Как кодировать в разных языках

Каждый язык программирования предоставляет встроенную функцию:

  • JavaScript — encodeURIComponent
  • PHP — urlencode
  • Python — urllib.parse.quote_plus
  • Java — URLEncoder.encode

Если вы формируете запрос вручную, используйте любой онлайн-сервис по запросу «url кодирование онлайн».

Проверить корректность запроса можно с помощью сервиса https://webhook.site. Он показывает полный запрос, включая заголовки и параметры.

Двойное кодирование для batch-запросов

Метод batch позволяет выполнить несколько запросов за один вызов. Запросы передаются в параметре cmd в виде строк: метод?параметр1=значение&параметр2=7. Но теперь каждая такая строка сама становится значением параметра. Поэтому ее тоже нужно кодировать.

  1. Сначала закодируйте значения внутри вложенного запроса.
  2. Затем закодируйте всю строку вложенного запроса целиком.

Если бы требовалось создать лид из примера выше в рамках пакетного выполнения запросов, URL выглядел бы так:

https://b24-abcdef.bitrix24.ru/rest/1/xxxxxxx/batch?cmd[0]=crm.lead.add%3Ffields%5BTITLE%5D%3DJohn%2526Martin
        

Обратите внимание: %26 превратилось в %2526, потому что символ % сам был закодирован как %25.

Чтобы избежать ручного кодирования и других сложностей, используйте готовые SDK. Они берут на себя всю работу с URL, кодированием и обработкой ошибок.

Официальные SDK Битрикс24:

Как передавать сложные структуры

Многие методы REST API принимают вложенные данные, например, список телефонов контакта или массив полей. В таких случаях рекомендуется отправлять POST-запросы с телом в формате JSON. Тогда структура сохраняется, и не нужно думать о кодировании отдельных параметров.

Пример лида с несколькими телефонами:

curl -X POST \
        -H "Content-Type: application/json" \
        -d '{
                "fields": {
                    "TITLE": "My company",
                    "PHONE": [
                        {
                            "VALUE": "112233",
                            "VALUE_TYPE": "WORK"
                        },
                        {
                            "VALUE": "555888112",
                            "VALUE_TYPE": "OTHER"
                        }
                    ]
                }
            }' \ 
        https://***/rest/***/crm.lead.add
        
$data = [
            "fields" => [
                "TITLE" => "My company",
                "PHONE" => [
                    [
                        "VALUE" => "112233",
                        "VALUE_TYPE" => "WORK"
                    ],
                    [
                        "VALUE" => "555888112",
                        "VALUE_TYPE" => "OTHER"
                    ]
                ]
            ]
        ];
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_USERAGENT, 'php script');
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_URL, 'https://***/rest/***/crm.lead.add');
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        $raw = curl_exec($ch);
        curl_close($ch);
        
data = {
            fields: {
                TITLE: 'My company',
                PHONE: [
                    {
                        VALUE: '112233',
                        VALUE_TYPE: 'WORK'
                    },
                    {
                        VALUE: '555888112',
                        VALUE_TYPE: 'OTHER'
                    }
                ]
            }
        };
        
        fetch('https://***/rest/***/crm.lead.add', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
        });
        
        
import requests
        
        data = {
            'fields': {
                'TITLE': 'My company',
                'PHONE': [
                      {
                            'VALUE': '112233',
                            'VALUE_TYPE': 'WORK'
                      },
                      {
                            'VALUE': '555888112',
                            'VALUE_TYPE': 'OTHER'
                      }
                ]
            }
        }
        
        r = requests.post('https://***/rest/***/crm.lead.add', json=data)
        
        

Если нет возможности отправить JSON, используйте GET-запрос или обычный POST-запрос. Данные нужно передавать в параметрах запроса, соблюдая правила кодирования.

GET-запрос

GET-запрос для примера выше:

https://***/rest/***/crm.lead.add.json?fields[TITLE]=My%20company&fields[PHONE][0][VALUE]=112233&fields[PHONE][0][VALUE_TYPE]=WORK&fields[PHONE][1][VALUE]=555888112&fields[PHONE][1][VALUE_TYPE]=OTHER
        

Как собрать такую строку программно:

  • PHP — функция http_build_query превращает массив в правильно закодированную строку.
  • JavaScript — можно использовать библиотеку qs или написать свою функцию.

POST-запрос

При POST-запросе нужно указать правильный заголовок Content-Type и отформатировать тело запроса.

  • application/x-www-form-urlencoded — данные преобразуются в одну строку
  • multipart/form-data — данные разбиваются на части, каждая имеет свои заголовки и отделена строкой-разделителем boundary=SomeBoundary
fields[TITLE]=My%20company&fields[PHONE][0][VALUE]=112233&fields[PHONE][0][VALUE_TYPE]=WORK&fields[PHONE][1][VALUE]=555888112&fields[PHONE][1][VALUE_TYPE]=OTHER
        
--SomeBoundary
        Content-Disposition: form-data; name="fields[TITLE]"
        
        My company
        --SomeBoundary
        Content-Disposition: form-data; name="fields[PHONE][0][VALUE]"
        
        112233
        --SomeBoundary
        Content-Disposition: form-data; name="fields[PHONE][0][VALUE_TYPE]"
        
        WORK
        --SomeBoundary
        Content-Disposition: form-data; name="fields[PHONE][1][VALUE]"
        
        555888112
        --SomeBoundary
        Content-Disposition: form-data; name="fields[PHONE][1][VALUE_TYPE]"
        
        OTHER
        --SomeBoundary
        

Порядок параметров

Некоторые методы, например, task.commentitem.add и task.checklistitem.complete, требуют строгого соблюдения порядка передачи параметров. В таких случаях параметры нельзя передавать по имени — как объект в JavaScript или ассоциативный массив в PHP. Иначе результат выполнения будет непредсказуем или метод вернет ошибку.

Для передачи таких параметров используйте массив с числовыми индексами. Индексы должны начинаться с 0.

Пример неправильного добавления комментария к задаче:

curl 'https://***/rest/***/task.commentitem.add?TASKID=123&FIELDS[POST_MESSAGE]=test'
        
CRest::call(
            'task.commentitem.add',
            [
                'TASKID' => 123,
                'FIELDS' => ['POST_MESSAGE' => 'text']
            ]
        );
        
BX24.callMethod(
            'task.commentitem.add',
            {
                TASKID: 123,
                FIELDS: { 'POST_MESSAGE': 'text' }
            }
        );
        

Пример правильного добавления комментария к задаче:

curl 'https://***/rest/***/task.commentitem.add?0=123&1[POST_MESSAGE]=test'
        
CRest::call(
            'task.commentitem.add',
            [
                123,
                ['POST_MESSAGE' => 'text']
            ]
        );
        
BX24.callMethod(
            'task.commentitem.add',
            [
                123,
                { 'POST_MESSAGE': 'text' }
            ]
        );