Клиент GWT не получает IncompatibleRemoteServiceException при изменении политики сериализации - PullRequest
2 голосов
/ 10 февраля 2012

При развертывании новой версии приложения с изменениями в классах модели (например, добавление / удаление полей).Клиент, у которого работает старая версия, получает com.google.gwt.user.client.rpc.SerializationException с RPC, созданным со старым клиентским кодом, и это ожидаемое поведение.В результате мы ожидаем увидеть IncompatibleRemoteServiceException на стороне клиента.Однако мы получаем StatusCodeException.

StatusCodeException - это ошибка 500, и мы не можем легко настроить поведение на стороне клиента (мы не хотим предполагать, что каждая ошибка StatusCodeException или 500 - это новая версия).Что мы можем делать здесь не так?

Примечание: на стороне сервера (log) мы получаем SerializationExcepion, очевидно, поскольку политика сериализации от старого клиента больше не действительна для нового сервера.Так почему бы не выбросить IncompatibleRemoteServiceException?

Спасибо.

1 Ответ

3 голосов
/ 25 августа 2012

Вот мое решение этой проблемы:

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

@Override
protected SerializationPolicy doGetSerializationPolicy(
        HttpServletRequest request, String moduleBaseURL, String strongName) {
    SerializationPolicy sp = super.doGetSerializationPolicy(request,
                                   moduleBaseURL, strongName);
    if(sp == null) { //no policy found, probably wrong client version
        throw new InvalidPolicyException();
    }
    return sp;
}

и

@Override
protected void doUnexpectedFailure(Throwable e) {
    if(e instanceof InvalidPolicyException) { 
        sendError(); //send message to reload client (wrong client version)
        return; //that's it
    }
    super.doUnexpectedFailure(e);
}

Закрытый метод sendError() - это, в основном, настраиваемая копия кода ошибки GWT 500 (извините за уродливый отступ Google))

private void sendError() {
    ServletContext servletContext = getServletContext();
    HttpServletResponse response = getThreadLocalResponse();
    try {
          response.setContentType("text/plain");
          response.setStatus(HttpServletResponse.SC_CONFLICT);
          try {
            response.getOutputStream().write("wrong client version".getBytes("UTF-8"));
          } catch (IllegalStateException e) {
            // Handle the (unexpected) case where getWriter() was previously used
            response.getWriter().write("wrong client version");
          }
        } catch (IOException ex) {
          servletContext.log(
              "sendError failed while sending the previous custom failure to the client", ex);
        }
}

Я использовал HttpServletResponse.SC_CONFLICT (409), но вы, вероятно, можете использовать умный код ошибки.Написанное сообщение не очень важно.

Тогда в вашем пользовательском RpcRequestBuilder (это код клиента)

public class CustomRequestBuilder extends RpcRequestBuilder {

 private class RequestCallbackWrapper implements RequestCallback {

        private RequestCallback callback;

        RequestCallbackWrapper(RequestCallback aCallback) {
            this.callback = aCallback;
        }

        @Override
        public void onResponseReceived(Request request, Response response) {
            if(response.getStatusCode() == 409) { //wrong client version
                Navigator.closeEveryPopUp();
                Navigator.showUncloseablePopUp("Login again!", 
                                new ClickHandler() {

                    @Override
                    public void onClick(ClickEvent event) {
                        //reload your $#%^ client!!!
                        Window.Location.reload();
                    }
                });
            } else {
                //(...)irrelevant security code here(...)
                callback.onResponseReceived(request, response);
            }

        }

        @Override
        public void onError(Request request, Throwable exception) {
            callback.onError(request, exception);
        }

 }

 @Override
 protected void doFinish(RequestBuilder rb) {
    //(...)more irrelevant security code here(...)
    super.doFinish(rb);
    rb.setCallback(new RequestCallbackWrapper(rb.getCallback()));
 }
}

Мы используем несколько всплывающих окон, это одна из причин для класса Navigator;конечно, используйте свой собственный стиль, чтобы предупредить пользователя.

EDIT : Что здесь происходит?

До GWT 1.3.3 IsSerializable был единственным доступным интерфейсомпометить класс как сериализуемый GWT RPC.Следующая версия принимала стандартный интерфейс Java Serializable для той же цели, но добавляла требование политики безопасности для объектов, реализующих этот интерфейс.По умолчанию GWT генерирует политику для каждой компиляции с уникальным хэш-именем.Старый клиент, пытающийся передать объект, помеченный как Serializable, на стороне сервера выдаст исключение политики сериализации, которое будет получено на стороне клиента как общая ошибка времени выполнения.IsSerializable позволяет старым клиентам по-прежнему использовать новые службы, пока подпись остается неизменной.Это означает, что альтернативное решение для этого вопроса - пометить каждый объект, проходящий через GWT RPC, как IsSerializable.Но если по какой-то причине вам нужно, чтобы ваши объекты не ссылались на интерфейс GWT, это хорошее решение для подключений старых клиентов.

Проверьте Руководство GWT для получения более подробной информации о 1.3.3 запасных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...