Bitrix24
Отладка приложения
Журнал моста, состояние токенов и разбор типичных ошибок: пустой фрейм, expired_token, insufficient_scope, ERROR_PLACEMENT_NOT_FOUND.
На этой странице · 11
Боевой Bitrix24 обмен BX24.js с порталом не показывает нигде: разработчик видит только последствия — «окно не изменило размер», «диалог не открылся». В демонстрационном портале виден сам кадр, и это главная отладочная ценность экрана.
Журнал моста
Кнопка «Журнал моста» в шапке демонстрационного портала открывает ленту кадров.
Каждая строка — один кадр: направление (in — от приложения, out — от портала),
APP_SID, команда или тип кадра, короткая сводка параметров. Строка раскрывается
в полный JSON. Лента ограничена 200 последними кадрами: приложение, вызывающее
resizeWindow в цикле, способно выдать тысячи кадров в минуту.
Что видно в журнале:
POST— отправка формы во фрейм со всеми полями, включаяPLACEMENT_OPTIONSименно в том виде, в каком его получило приложение;hello— библиотека загрузилась и просит окружение;init— ответ портала: токены, домен, язык, признак первого запуска, точка встраивания и её js-интерфейс;- каждая команда
BX24.*, ушедшая через мост, и результат по ней. Ошибка красится отдельно.
Команда, которой портал не знает, возвращается кадром с кодом UNKNOWN_COMMAND
и текстом «Портал не знает команду «…»».
Приложение не вышло на связь
Если за 8 секунд от фрейма не пришло ни одного кадра, портал показывает подсказку. Порядок проверки в ней тот же, что стоит держать в голове:
- 1
Обработчик отвечает на POST
Портал открывает приложение POST-запросом, а не GET. Обработчик, который умеет только GET, отдаст 404 или 405, и во фрейме будет пусто.
- 2
Страница подключает библиотеку и вызывает
BX24.init()Адрес библиотеки —
<адрес стенда>/api/v1/, он же показан в панели «Портал песочницы» на экране «Локальные приложения». - 3
Приложение не запрещает фрейминг
X-Frame-Options: SAMEORIGINили CSP без нужногоframe-ancestors— и браузер не покажет страницу. Портал об этом не узнает: проверку делает браузер, и в бою будет ровно то же самое.
Если приложение открыто напрямую, вне фрейма, библиотека пишет в консоль
предупреждение: методы, которым нужен портал, вернут ошибку, а getAuth(),
getDomain(), getLang() и isAdmin() отдадут пустые значения. Отдельное
предупреждение — на потерянный APP_SID: связаться с порталом нечем.
Состояние приложения
В карточке приложения видно то, чего в бою не видно нигде:
- Токены — последние выданные пары целиком, с обратным отсчётом и состоянием
«Действует», «Истёк» или «Отозван». Копируются кнопкой: тот же токен подставляется
в
curl. - Виджеты и Подписки на события — что приложение успело зарегистрировать
через
placement.bindиevent.bind. - Открытия во фрейме — последние сессии с их
APP_SID, точкой встраивания и отметкой, была ли это установка.
Запросы приложения попадают в общий журнал на экране «Логи запросов». Ответы,
которые сформировал портал, помечены заголовком X-APIStend-Source: app-context
и X-APIStend-App с client_id; их тело сохраняется в журнале целиком, потому что
из спецификации оно не восстанавливается.
Типичные ошибки
expired_token на каждый вызов
Токен просрочен или замещён обновлением. Правильная реакция — обменять
refresh_token на новую пару и повторить вызов; обновлять по расписанию нельзя.
В браузере это делает сама библиотека: получив expired_token, BX24.js просит у портала
свежий токен через мост и повторяет вызов ровно один раз. Второй такой ответ уходит
приложению как есть. client_secret в браузер при этом не попадает и попадать
не должен.
Проверяется коротким сроком токена в карточке приложения (от 5 секунд) или кнопкой «Состарить сейчас».
NO_AUTH_FOUND вместо expired_token
Это другая ошибка: токена не существует, он отозван или приложение удалено. Обновлять нечего — нужно пройти цикл OAuth заново. Токены отзываются при удалении приложения и при сбросе установки.
insufficient_scope
У приложения нет права на этот метод. Права определяются по префиксу: crm.* требует
crm, task.* — task. Проверить, не вызывая метод, можно через method.get —
он вернёт isAvailable: false.
Добавленное в карточке право действует сразу, в том числе для уже выданных токенов:
проверка идёт по карточке приложения. А вот поле scope уже выданной пары останется
прежним: оно снято в момент выдачи и переносится при обновлении по refresh_token.
Свежий набор придёт с новой парой — например, при следующем открытии фрейма.
ERROR_PLACEMENT_NOT_FOUND
placement.bind отвечает так и на неизвестный код, и на код, право для которого
приложению не выдано. Боевой портал эти случаи тоже не разделяет. Сверяйте код
вызовом placement.list — он показывает только те точки, которые доступны
этому приложению.
Рядом ещё две ошибки того же метода: ERROR_UNSUPPORTED_PROTOCOL, если адрес
обработчика не http и не https, и ERROR_PLACEMENT_MAX_COUNT, если для точки
уже зарегистрировано столько обработчиков, сколько она допускает.
Про localhost в placement.bind
Единственное намеренное отличие от боевого портала: ERROR_WRONG_HANDLER_URL
на локальный адрес здесь не выдаётся. Ради этого продукт и существует.
Виджет зарегистрирован, но его нет
placement.bind вернул true, регистрация видна в placement.get, вкладки в карточке
сделки нет. Значит, приложение не завершило установку: до BX24.installFinish()
портал не показывает виджеты и не доставляет события. Проверяется полем INSTALLED
в app.info.
Ответ не тот, что ожидался, а метод портальный
Заголовок X-Mock-Scenario действует раньше контекста приложения: при любом сценарии,
кроме success, отвечает шлюз, а не портал. app.info со сценарием rate_limit
вернёт QUERY_LIMIT_EXCEEDED, а не состояние приложения. Тот же эффект даёт
ненулевая доля случайных ошибок на экране «Ключи и токены» — она действует на весь шлюз,
включая placement.bind и event.bind.
redirect_uri уходит куда попросили
APIStend не сверяет redirect_uri с карточкой приложения и вернёт код по любому
переданному адресу. Боевой портал так не делает: он redirect_uri в запросе
не принимает вовсе и всегда возвращает код на адрес из карточки. Приложение, которое
здесь получает код на «удобный» адрес, в бою получит его на другой — проверяйте
цикл с тем адресом, который стоит в карточке.