Ошибка при загрузке виджета
Closed this issue · 9 comments
Ситуация
Есть headless сайт на Next.js. Бэкенд сделан на Kirby CMS. На сайте есть небольшой интернет-магазин. Пытаюсь интегрировать туда виджет для расчета стоимости доставки и выбора адреса.
Проблема
На тестовом API (https://api.edu.cdek.ru/v2) и с тестовыми ключами получилось все наладить. Несколько дней назад попробовали перейти на боевое API и настоящие ключи и — виджет перестал открываться. Выглядит это так:
Возможные причины
В попытках разобраться обнаружил, что поведение виджета на этом сайте отличается от ожидаемого поведения. Чистая минимальная установка виджета работает так:
На скриншоте видно, что скрипт отправляет 16 запросов вида ?is_handout=true&action=offices&page=15&size=500
. Ответ на каждый запрос весит в районе 120 кб (что и так довольно много), но все ответы приходят и виджет открывается.
Для чистоты эксперимента сделал новый проект на Next.js и засетапил в нем такой же минимальный код виджета. По каким-то необъяснимым причинам в таких условиях виджет отправляет аналогичный запрос, но без параметра size=500
. Результат — огромный ответ от сервера иногда до 15 МБ (!!!), который роняет пребек (на next api routes) и виджет не открывается. Запрос видно на скриншоте:
Аналогичный запрос напрямую к серверу service.php выдает ошибку. Пару раз возвращался ответ гигантского размера (больше 10 МБ, что абсолютно неприемлемо в любом случае).
Возможное решение
Убедиться, что виджет всегда отправляет запрос с лимитом size=500
.
Код, чтобы воспроизвести ошибку:
- Делаем новый проект на next.js
npx create-next-app@latest
. В качетсве роутера выбираем pages router - pages/index.js:
import Script from "next/script"
import { useState } from "react"
export default function test(params) {
const [widget, setWidget] = useState()
function initCDEK() {
setWidget(
new window.CDEKWidget({
from: "Санкт-Петербург",
root: "cdek-map",
apiKey: "ключ от яндекс карт",
servicePath: "http://localhost:3001/api/service",
defaultLocation: "Санкт-Петербург",
popup: true,
})
)
}
return (
<div>
<Script src="https://cdn.jsdelivr.net/npm/@cdek-it/widget@3" onReady={initCDEK} />
<button
onClick={() => {
widget.open()
}}>
Open widget
</button>
</div>
)
}
- Файл pages/api/service.js (пребек):
import axios from "axios"
export default function handler(request, response) {
if (request.method === "GET") {
try {
axios({
method: "GET",
url: `https://api.badgallery.com/api/cdek/service`,
params: request.query,
})
.then(res => {
response.status(200).json(res.data)
})
.catch(error => {
response.status(500).json(error)
console.log(error)
})
} catch {
response.status(500).json({ error: "request failed" })
}
} else if (request.method === "POST") {
try {
axios
.request({
method: "POST",
url: `https://api.badgallery.com/api/cdek/service`,
data: request.body,
})
.then(res => {
response.status(200).json(res.data)
})
.catch(error => {
response.status(500).json(error)
console.log(error)
})
} catch {
response.status(500).json({ error: "request failed" })
}
} else {
// This handler doesn't handle anything but GET request
response.status(500).json({ error: "Not handled" })
}
}
По адресу https://api.badgallery.com/api/cdek/service запускается скрипт service.php
к рабочими ключами из ЛК.
Ссылка на демо, где можно посмотреть, как виджет не работает онлайн :))
Добрый день.
На скриншоте видно, что скрипт отправляет 16 запросов вида ?is_handout=true&action=offices&page=15&size=500. Ответ на каждый запрос весит в районе 120 кб (что и так довольно много), но все ответы приходят и виджет открывается.
Результат — огромный ответ от сервера иногда до 15 МБ (!!!), который роняет пребек (на next api routes) и виджет не открывается
С версии 3.9 как раз была реалзиована пагинация, чтобы не тянуть весь объем целиком. С тестовой средой работает просто потому, что там представлены не все офисы из продовой среды, а значит объем меньше. Сократить его прямо сейчас возможности нет (этот вопрос обсуждался в #34).
Отправка запроса с ?is_handout=true&action=offices&page=0
была реализована для обратной совместимости бэкендов виджета. На сколько вижу, пребэк реализован по мотивам версий до 3.9.
Как это рабоатет сейчас: виджет отправляет запрос на получение первой страницы и ожидает в ответ заголовки x-current-page
и x-total-pages
. Если их не пришло - считаем, что используется старый бэк и надо спрашивать 0 страницу со всеми офисами. Иначе вычисляем число страниц и запрашиваем каждую.
Соответственно, чтобы переключиться на новую версию бэкенда с пагинацией - необходимо прокидывать эти два нужных заголовка. Или вообще переписать бэкенд на JS (по факту - это ведь тот же прокси до апи2)
Похоже, у меня эта же ошибка. На боевом апи script.php стал возвращать Server not authorized to CDEK API
, хотя ещё неделю назад всё работало нормально. При переключении на тестовое апи ошибка исчезает.
На боевом апи script.php стал возвращать Server not authorized to CDEK API
С какой версией виджета?
На боевом апи script.php стал возвращать Server not authorized to CDEK API
С какой версией виджета?
Пробовал на 3.9.1 и 3.9.3
Пробовал на 3.9.1 и 3.9.3
А версия бэкенда от какого?
Пробовал на 3.9.1 и 3.9.3
А версия бэкенда от какого?
script.php тех же версий
Такая же проблема, решение не найдено
Похоже, у меня эта же ошибка. На боевом апи script.php стал возвращать
Server not authorized to CDEK API
, хотя ещё неделю назад всё работало нормально. При переключении на тестовое апи ошибка исчезает.
Разобрались, оказывается менеджер в ЛК нажал на кнопку "обновить ключи" и старые стали недействительными 🤦♂️