Как вернуть пользовательские коды ошибок в облачных конечных точках?

1

Как описано здесь https://cloud.google.com/appengine/docs/java/endpoints/exceptions Google Cloud Endpoints возвращает только очень ограниченный диапазон кодов статуса http, а именно:

HTTP 400 BadRequestException
HTTP 401 UnauthorizedException
HTTP 403 ForbiddenException
HTTP 404 NotFoundException (also: Timeout)
HTTP 405
HTTP 408
HTTP 409 ConflictException
HTTP 410
HTTP 412
HTTP 413

Google предлагает использовать существующие коды статуса для возврата пользовательских ошибок:

"Во многих ситуациях вы можете использовать общие коды состояния HTTP, чтобы указывать на успех или неудачу запроса API-пользователя. Например, если пользователь пытается получить сущность, которая не существует, вы можете отправить HTTP-запрос 404, если не существует сущности с идентификатором: entityId. Вы можете отправить такие общие коды состояния HTTP, выбросив исключение, предоставляемое библиотекой конечных точек, следующим образом:

String message = "No entity exists with ID: " + entityId;
throw new NotFoundException(message);

"

Далее в том же документе Google заявляет:

"Любые другие коды HTTP 4xx будут возвращены как ошибка 404"

В чем проблема? Я бросаю 404, если моя сущность не может быть найдена, но Google также выбрасывает 404 для почти всего остального, что не так.

За исключением 401, 403 и 409, которые я могу использовать, чтобы сообщить моему клиенту, что такое точная ошибка (авторизация, запрет или конфликт), мне нужно вернуться к 400 и 404 для всех моих других кодов статуса, результат мой клиент никогда точно не знает, в чем проблема.

Конечно, я могу включить человекообразное сообщение об ошибке, но это предназначено для RuntimeException (ов), которое произошло в коде сервера, а не для того, чтобы сообщить моему клиенту, что проблема связана с переданными им данными.

Конечно, я также могу использовать первые несколько цифр описания ошибки, чтобы отправить код ошибки, специфичный для приложения, и отправить общий 400 Bad Request, но я думаю, что не так, как это должно быть сделано.

Любой вход оценивается. Как вы возвращаете специальные коды ошибок приложения, которые ваш клиент может использовать для решения конкретной проблемы?

Теги:
exception-handling
rest
google-app-engine
google-cloud-endpoints

1 ответ

1

Прочитав следующие и другие сообщения

Я бы почти сказал, что Google предлагает неправильно, потому что нет четкой дифференциации между кодами статуса http и кодами приложений. Оба варианта выполняются на разных уровнях, и клиент не может сказать, сделал ли он плохой запрос, например, нарушил контракт (например, вызвал несуществующую конечную точку, по существу, ошибку времени выполнения) или передал неправильный идентификатор (прикладной уровень ошибка).

В статьях предлагаются следующие решения:

  • используйте коды ошибок HTTP: не всегда возможно, как описано выше
  • добавьте ошибку приложения как пользовательский заголовок ответа: я бы не выбрал это, потому что он не появится в журнале, что сделает отладку жесткой.
  • всегда возвращайте 200 и оберните результат в JSON (как это делает сокеты): небезопасно с конечными точками

Я придумал другое решение, которое, как я признаю, является компромиссом (на самом деле является нарушением сообщения об ошибке), но я считаю, что это лучшая подходящая интеграция отдельных кодов ошибок приложения в Cloud Endpoints:

  • Я расширил 400 BadRequestException, так что любое сообщение об ошибке возвращается как JSON. Клиент по-прежнему получает код http-статуса 400, но вместо сообщения об ошибке String он получает строку JSON, такую как:

{"code": 400, "message": "Это сообщение с возможностью чтения человеком". }

И здесь у меня есть два варианта: либо я возвращаю код 400, что означает, что это исключение BadRequestException, когда клиент фактически нарушил контракт, или я возвращаю любой другой код приложения, который клиент может легко разобрать и обработать.

My ApplicationException выглядит так (он использует пользовательский JSONizer, поэтому он не будет работать для вас так, но вы можете использовать JSONObject, GSON, Jackson, что угодно):

import com.google.api.server.spi.response.BadRequestException;

public class ApplicationException extends BadRequestException {
    private static final int DEFAULT_APPLICATION_CODE = 400; // use this code for all requests without explicit code

    public ApplicationException(int code, String message) {
        super(JsonResponse.build()
                .add("code", code)
                .add("message", message)
                .toString());
    }
    public ApplicationException(String message) {
        super(JsonResponse.build()
                .add("code", DEFAULT_APPLICATION_CODE)
                .add("message", message)
                .toString());
    }
    public ApplicationException(String message, Throwable cause) {
        super(JsonResponse.build()
                .add("code", DEFAULT_APPLICATION_CODE)
                .add("message", message)
                .toString());
    }

}

Я не поставил свой ответ так правильно, что хочу, чтобы вы продолжали публиковать дальнейшие предложения и комментарии, если считаете, что есть лучшие способы сделать это.

  • 0
    Я только что заметил, что строка JSON заканчивается на кавычках на стороне клиента. Конечные точки, вероятно, пытаются проанализировать сообщение как Json, а не просто передать строку, поэтому нам будет хорошо, если мы введем объект, но это невозможно, поскольку подпись принимает только строку. Все еще расследую.
  • 0
    В итоге я возвратил что-то вроде 400 This is a human readable error message. вместо { "code": 400, "message": "This is a human readable error message." } - не очень хорошее решение, но, по крайней мере, анализируемое и четкое разделение ошибок сетевого уровня и приложений.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню