Description
Ситуация
Есть 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
к рабочими ключами из ЛК.