8.1 KiB
Требования к серверу App Store для совместимости с F7cloud
Чтобы клиент F7cloud корректно работал с вашим appstore, сервер должен соблюдать следующие условия.
Изменения в клиенте (для совместимости с кастомным appstore) зарегистрированы в CHANGELOG-APPSTORE.md.
1. Формат тела ответа GET /api/v1/apps.json
Клиент делает:
responseJson['data'] = json_decode($response->getBody(), true)
То есть в data попадает весь распарсенный JSON-ответ.
Сейчас у вас:
Тело ответа: {"data": [{"id": "spreed", "releases": [...], ...}]}
После парсинга в data попадает объект { data: [ ... ] }. В коде клиента по этому объекту идёт цикл foreach ($response['data'] as $app), и в первой итерации $app оказывается массивом приложений, а не одним приложением. У массива нет ключа releases → ошибка.
Что нужно на appstore:
Тело ответа должно быть массивом приложений в корне, без обёртки {"data": ...}.
Неправильно (как сейчас):
{"data":[{"id":"spreed","releases":[...],...}]}
Правильно:
[{"id":"spreed","releases":[...],...}]
То есть ответ GET /api/v1/apps.json должен отдавать JSON-массив приложений, а не объект с полем data.
2. Ответ 200 и автоматическое заполнение кэша
Кэш на стороне F7cloud заполняется сам: при ответе 200 OK с телом клиент сохраняет полученный JSON в свой кэш. Вручную заполнять кэш на клиенте не нужно — достаточно, чтобы appstore отдавал 200 с полным массивом приложений.
Ответ 304 Not Modified
При ответе 304 Not Modified клиент не получает новое тело, а подставляет в data своё сохранённое содержимое кэша. Если кэша ещё не было (первый запрос или кэш пустой), подставляется пустая строка → json_decode('') → null → пустой список приложений и ошибка «приложение не найдено».
Что нужно на appstore:
Для GET /api/v1/apps.json не отдавать 304, когда у клиента ещё нет валидного кэша. Проще всего: по умолчанию всегда отдавать 200 с полным телом (полным массивом приложений). Тогда клиент при первом же запросе получит данные и сам заполнит свой кэш.
Если решите поддерживать 304, отдавайте его только когда запрос содержит заголовок If-None-Match с актуальным ETag и контент не менялся.
3. Структура каждого приложения в массиве
У каждого элемента массива приложений должно быть поле releases — массив (хотя бы пустой []). Клиент делает foreach ($app['releases'] as $release) без проверки; при отсутствии или null возникает ошибка.
Обязательно у каждого приложения:
id— идентификатор приложенияreleases— массив релизов (минимум[])- в каждом элементе
releases— поля в формате F7cloud (version, download, signature, certificate и т.д.)
4. Заголовки ответа
- Content-Type:
application/json - При необходимости кэширования по ETag — заголовок ETag в ответе 200. Тогда клиент сможет при следующем запросе передать
If-None-Matchи при неизменном контенте получить 304 (с учётом п. 2 — только когда у клиента уже есть валидный кэш).
5. Сертификат и подпись: символы \r\n (перенос строки)
В ответе у вас в полях certificate и signature встречаются последовательности \r\n (CRLF — перевод строки в стиле Windows). В JSON они приходят как экранированные \r\n и после json_decode() превращаются в реальные символы CR и LF в строке.
Как ведёт себя F7cloud (без изменений в коде):
-
Сертификат — передаётся как есть в
openssl_get_publickey(),openssl_x509_parse()и в phpseclibloadX509(). Формат PEM допускает и\n(LF), и\r\n(CRLF) между строками. OpenSSL такие сертификаты обрабатывает нормально, проблемой это не является. -
Подпись — строка передаётся в
base64_decode($app['releases'][0]['signature']). В PHP в режиме по умолчаниюbase64_decode()игнорирует пробельные символы (в т.ч.\r,\n, пробелы) внутри base64-строки (по RFC 2045). То есть подпись с переносами строк обрабатывается корректно.
Итог: F7cloud такие значения обрабатывает, менять что-то на клиенте из-за \r\n не нужно.
Рекомендация для appstore (по желанию): для единообразия и совместимости с разными клиентами можно:
- в сертификате (PEM) использовать только
\n(LF), без\r; - в подписи (base64) хранить/отдавать одну строку без переносов (как одну длинную base64-строку).
Это не обязательно для F7cloud, но упрощает отладку и совместимость с другими системами.
Краткий чек-лист для сервера appstore
- Тело
GET /api/v1/apps.json— JSON-массив приложений в корне:[{...}, {...}], а не{"data": [...]}. - По умолчанию отдавать 200 с полным массивом приложений — кэш на стороне F7cloud заполнится сам. 304 отдавать только при наличии у клиента валидного кэша (If-None-Match + неизменный контент).
- У каждого приложения в массиве есть поле
releases(массив, не null и не отсутствует). - Ответ с Content-Type: application/json.
\r\nв сертификате и подписи — F7cloud обрабатывает (OpenSSL принимает CRLF в PEM, base64_decode игнорирует пробелы). Менять не обязательно; при желании можно отдавать сертификат с\nи подпись без переносов.
После этих изменений на стороне appstore клиент F7cloud будет корректно получать и обрабатывать список приложений без изменений в коде клиента.