Исключения
Всё, что бросает SDK, наследует S5wException. Класс исключения говорит, что случилось;
текст сообщения предназначен для логов. Как обрабатывать на практике — в руководстве
Обработка ошибок.
Иерархия
S5wException RuntimeException; корень всех ошибок SDK
├── TransportException сервер не ответил: DNS, отказ соединения, таймаут
├── ResponseException ответ пришёл, но не в формате S5W
├── ApiException сервер ответил кодом ошибки
│ ├── UnauthorizedException 401 ключа нет или сервер его не знает
│ ├── ForbiddenException 403 ключ отключён, истёк или BASIC там, где нужен FULL
│ ├── NotFoundException 404 нет файла, папки или сессии
│ ├── ConflictException 409 имя занято; часть не продолжает загрузку
│ ├── PayloadTooLargeException 413 квота заполнена; часть слишком большая
│ ├── ValidationException 422 параметры не прошли проверку
│ └── ServerException 5xx сбой на стороне сервера
├── UploadInterruptedException загрузка частями прервана, сессию можно продолжить
└── UploadUnconfirmedException сборка файла запрошена, но не подтвержденаS5wException
Корень иерархии, наследник RuntimeException. Поймав его, вы поймаете любую ошибку SDK.
Бросается и напрямую — для ошибок, которые SDK обнаруживает до запроса: неверная
конфигурация, файл не читается с диска, файл изменился во время загрузки, размер файла не
совпадает с сессией при resume().
Сообщение
Сообщения имеют вид S5W {путь}: {статус} {текст сервера}:
S5W v1/files/7CKEKbaV8AN6qTs1: 404 File does not exist
S5W v1/folders: 409 Folder "avatars" already exists
S5W v1/files: 422 Folder "no-such" does not exist
S5W v1/check: simulated: connection refusedПуть показывается раскодированным — кириллица в имени папки читается как есть.
ApiException
Сервер ответил статусом ошибки. Тело ответа — { code, message, errors? }. Для статусов из
таблицы ниже бросается наследник; для остальных (например, 400) — сам ApiException.
| Статус | Класс | Типичные причины |
|---|---|---|
| 400 | ApiException |
пустая часть или часть меньше 4 МиБ, но не последняя |
| 401 | UnauthorizedException |
ключа нет или он неизвестен |
| 403 | ForbiddenException |
ключ отключён или истёк; ключ BASIC для folders(), files(), uploads() |
| 404 | NotFoundException |
нет файла, папки, сессии; неверный формат id файла (без запроса) |
| 409 | ConflictException |
имя папки или файла занято; смещение части не совпало; complete() до получения всех байт |
| 413 | PayloadTooLargeException |
квота бакета заполнена; часть больше 16 МиБ или выходит за заявленный размер |
| 422 | ValidationException |
поле не прошло проверку; нет папки; опции картинки для не-картинки; хеш не совпал |
| 5xx | ServerException |
ошибка сервера; 507 — на диске сервера нет места |
Методы
status(): int — HTTP-статус ответа.
errors(): array<string, list<string>> — ошибки по полям; заполнено только для 422 с
ошибками валидации полей.
method(): string — HTTP-метод запроса, например "PUT".
path(): string — путь запроса относительно адреса сервера, например "v1/files/7CKEKbaV8AN6qTs1".
catch (ApiException $e) {
$e->status(); // 409
$e->method(); // "POST"
$e->path(); // "v1/folders"
}ValidationException
Дополнительный метод errorsOf(string $field): list<string> — ошибки одного поля.
catch (ValidationException $e) {
$e->errors(); // ["name" => ["must not be blank", "size must be between 1 and 100"]]
$e->errorsOf('name'); // ["must not be blank", "size must be between 1 and 100"]
$e->errorsOf('other'); // []
}Если ошибка относится ко всему запросу, а не к полю (нет папки, хеш не совпал), errors()
пустой, а причина — в сообщении.
TransportException
Запрос не получил HTTP-ответа: сервер не найден, соединение отклонено, истёк таймаут. Единственный вид сбоя, который стоит повторять как есть.
Методы
isTimeout(): bool — true, если причина — истёкший таймаут, а не отказ соединения.
Исходное исключение HTTP-клиента доступно через getPrevious().
ResponseException
Ответ пришёл, но это не ответ S5W: не JSON, нет нужного поля, у поля не тот тип. Обычно адрес указывает не на S5W (например, на страницу ошибки прокси) или версии сервера и SDK не совпадают. В сообщении — путь к полю:
S5W v1/check: the answer is not JSON
S5W v1/check: bytes.quota must be int, got stringUploadInterruptedException
Загрузка частями остановилась на сбое сети или сервера после того, как все попытки
(Uploads::ATTEMPTS) закончились. Сессия на
сервере сохранена — её можно продолжить в течение 24 часов после последней полученной части.
Бросается методами uploads()->send(), sendContent(), resume(), а также
files()->upload() и uploadContent() для файлов больше порога загрузки частями.
Методы
sessionId(): string — id сессии; передайте в uploads()->resume().
offset(): int — сколько байт, насколько известно SDK, уже на сервере.
size(): int — полный размер файла.
Причина — в getPrevious(): TransportException, ServerException или ConflictException.
catch (UploadInterruptedException $e) {
$file = $s5w->uploads()->resume($e->sessionId(), $path);
}UploadUnconfirmedException
Все байты переданы и сборка файла запрошена, но ответ не пришёл (обрыв связи, ошибка шлюза), а сессии на сервере уже нет. Файл мог быть создан — тогда его id неизвестен; мог и не быть. SDK не пытается угадать: поиск по имени мог бы найти чужой файл.
Методы
sessionId(): string — id сессии, которой больше нет.
name(): string — имя, с которым начиналась загрузка. Сохранённое имя может отличаться —
например, name (1).ext, если имя было занято.
catch (UploadUnconfirmedException $e) {
$logger->error("Загрузка {$e->name()} не подтверждена — проверьте папку вручную");
}Что бросают методы
| Метод | Характерные исключения |
|---|---|
S5w::check() |
UnauthorizedException, ForbiddenException |
Folders::create(), rename(), update() |
ConflictException, ValidationException, NotFoundException |
Folders::get(), delete() |
NotFoundException |
Files::get(), delete() |
NotFoundException |
Files::list() |
ValidationException (нет папки) |
Files::rename(), move(), update() |
NotFoundException, ValidationException, ConflictException |
Files::upload(), uploadContent() |
ValidationException, PayloadTooLargeException; для больших файлов — как у send() |
Uploads::start() |
ValidationException, PayloadTooLargeException, ServerException (507) |
Uploads::append() |
ConflictException, PayloadTooLargeException, ApiException (400), NotFoundException |
Uploads::complete() |
ConflictException, ValidationException |
Uploads::send(), sendContent() |
UploadInterruptedException, UploadUnconfirmedException, ApiException |
Uploads::resume() |
как у send(), плюс NotFoundException и S5wException (другой файл) |
Любой метод, который ходит на сервер, может также бросить TransportException,
ResponseException, UnauthorizedException и ForbiddenException.