Не работает AJAX-запрос - разбор причин
Запрос уходит, а на странице ничего не меняется: ответа нет, он пустой или не разбирается. Разбираем причины по убыванию частоты.
С чего начать
Смотрим сырой ответ, а не то, что показал скрипт:
curl -s -X POST 'https://example.com/bitrix/services/main/ajax.php?action=local:feedback.feedback.save' \ -d 'name=test' | head -c 400# в ответе должен быть только JSON вида {"status":...,"data":...,"errors":[...]}# любая строка до открывающей скобки ломает разбор ответа на стороне браузераСырой ответ отвечает сразу на два вопроса: дошёл ли запрос и что вернул сервер. Предупреждение PHP или кусок разметки перед данными объясняют почти половину жалоб «ответ пришёл, но скрипт его не понял».
Читаем описание ошибки на стороне браузера:
BX.ajax.runAction('local:feedback.feedback.save', { data: { name: 'test' } }) .then((r) => console.log('ответ', r.data)) .catch((r) => console.log('ошибки', r.errors)); // здесь код и текст отказаПлатформа возвращает ошибки списком, с кодом и текстом. Ненайденное действие, отклонённая подпись и нехватка прав различаются именно здесь, а не по внешнему поведению страницы.
Проверяем подпись запроса:
// легаси-файл, а не контроллер: проверки пишут рукамиif (!check_bitrix_sessid()) { http_response_code(403); // ключ не передан или уже не тот exit;}// в форму ключ ставят вызовом bitrix_sessid_post(), в запрос - BX.bitrix_sessid()Проверка сверяет параметр запроса или заголовок с ключом текущей сессии. Ключ меняется при входе и выходе, поэтому страница, открытая до входа, шлёт уже недействительный ключ.
Ищем лишний вывод в своём коде:
grep -rn 'var_dump\|print_r\|echo ' /home/bitrix/www/local/php_interface/ | headtail -20 /var/log/php-fpm/bx0-error.log | grep -i 'warning\|notice'# предупреждение PHP попадает в тело ответа наравне с данными# разбор JSON после такой строки падает уже на стороне браузераОтладочная печать в обработчике портит все ответы сайта сразу, а не только свои. Это же относится к пробелу перед открывающим тегом в подключаемом файле: он уезжает в ответ первым символом.
Причины
-
В ответе есть лишний вывод примерно 30% случаев
ПризнакОтвет приходит, но скрипт сообщает о неразобранном ответе или молча ничего не делает.
ПроверкаСмотрим сырой ответ запросом из консоли и читаем его первые символы.
Что делатьУбираем отладочную печать и предупреждения PHP, а в подключаемых файлах - пробелы перед тегом.
-
Действие не найдено примерно 25% случаев
ПризнакВ ответе описание ошибки о ненайденном действии или обычная страница вместо данных.
ПроверкаСверяем идентификатор действия с пространством имён, классом и методом контроллера.
Что делатьПравим идентификатор и проверяем автозагрузку класса: без неё контроллер не находится.
-
Запрос отклонён проверкой подписи примерно 20% случаев
ПризнакОтказ приходит и до выполнения кода действия, чаще после входа или выхода на другой вкладке.
ПроверкаСмотрим, передаётся ли ключ сессии в запросе, и сравниваем его с текущим значением.
Что делатьПередаём ключ штатным способом и перезагружаем страницу после смены пользователя.
-
Действию не хватает прав примерно 15% случаев
ПризнакУ авторизованного всё работает, а гость получает отказ или страницу входа вместо данных.
ПроверкаПроверяем правила доступа действия и права группы на нужный раздел данных.
Что делатьРазрешаем действие гостю осознанно либо возвращаем понятную ошибку вместо молчания.
-
Запрос уходит не на тот адрес примерно 10% случаев
ПризнакВ консоли браузера видна ошибка смешанного содержимого или запрет обращения к чужому домену.
ПроверкаСмотрим полный адрес запроса во вкладке сети: протокол, домен и путь.
Что делатьСтроим адрес средствами платформы, а не собираем строкой: домен и протокол подставятся сами.
Частые вопросы
Почему в ответе приходит целая страница?
Запрос попал не на действие контроллера, а на обычную страницу сайта: неверный адрес или ошибка в идентификаторе действия. Сырой ответ показывает это сразу.
Как передать ключ сессии в запросе?
Штатными средствами: в форме - служебным вызовом, в запросе из скрипта - значением ключа текущей сессии. Проверка сверяет параметр запроса или заголовок с этим значением.
Можно ли отключить проверку подписи?
Технически да, но у изменяющих данные действий это прямая уязвимость. Снимать проверку допустимо только у действий, которые ничего не меняют.
Почему запрос работает у администратора?
У него достаточно прав, и правила доступа действия отрабатывают тихо. Проверять такие сценарии надо в отдельном окне без входа на сайт.
Где смотреть ошибку, если в консоли пусто?
В журнале процессов PHP и в журнале платформы: фатальная ошибка внутри действия не всегда доезжает до браузера в читаемом виде.
Смежное
- Подгрузка списка порциями: кнопка «Показать ещё» и прокрутка - типовой сценарий догрузки списка
- AJAX на практике - оглавление подтемы
- Cannot read properties of undefined: разбор причин на витрине - если падает разбор ответа на клиенте
- AJAX-запрос: контроллер, свой файл и ответ в JSON - как устроен правильный запрос
- Отправка формы через AJAX: проверка полей, защита, ответ с ошибками - форма и её проверки
- AJAX-действия своего компонента: действия, параметры, ошибки - когда запрос идёт в действие компонента
- Данные от посетителя: экранирование, проверка, сеанс - зачем нужна подпись запроса
- Своё расширение JS: каталог, зависимости, подключение - где живёт вызывающий скрипт
- Отладка на боевом сайте: журналы, режим ошибок, поиск виновника - журналы при пустом ответе
- Ядро JS и BX.ajax - устройство клиентских вызовов
- Контроллер изнутри: маршрут, действие, фильтры, ответ - где в цепочке запрос обрывается
- Ошибка проверки источника запроса: разбор причин - если дело именно в подписи сеанса