当部署新版本的应用程序并更改模型时 类(例如添加/删除字段)。 运行旧版本的客户端获取 RPC 中的 com.google.gwt.user.client.rpc.SerializationException 使用旧的客户端代码制作,这是预期的行为。 因此,我们希望在客户端看到 IncompleteRemoteServiceException。 但是我们得到 StatusCodeException。
StatusCodeException 是 500 错误,我们无法自定义客户端 很容易出现副作用(我们不想假设每个 StatusCodeException 或 500 错误是新版本)。我们能做什么 这里做错了吗?
注意:在服务器端(日志),我们显然得到了 SerializationExcepion,因为旧客户端的序列化策略对新服务器不再有效。那么为什么不抛出 IncompleteRemoteServiceException 呢?
谢谢。
最佳答案
这是我面临该问题的解决方案:
首先扩展RemoteServiceServlet
(所有服务 servlet 都将从这个新类扩展,记住这是服务器代码)。这是其中的相关代码:
@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);
}
私有(private)方法 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 类的原因之一;当然,使用您自己的样式来警告用户。
编辑:这里发生了什么?
直到 GWT 1.3.3,IsSerialized
是唯一可用于将类标记为 GWT RPC 可序列化的接口(interface)。出于相同目的,下一个版本接受了 Java 标准 Serialized
接口(interface),但添加了实现此接口(interface)的对象的安全策略要求。默认情况下,GWT 为每个编译生成一个具有唯一哈希名称的策略。尝试传输标记为可序列化的对象的旧客户端将在服务器端抛出序列化策略异常,该异常将在客户端作为通用运行时错误接收。 IsSerialized
允许旧客户端仍然使用新服务,只要签名保持不变。这意味着此问题的替代解决方案是将通过 GWT RPC 的每个对象标记为 IsSerialized
。但是,如果由于某种原因您需要不引用 GWT 接口(interface)的对象,那么这对于旧客户端连接来说是一个很好的解决方案。
检查GWT's guide有关 1.3.3 回退的更多详细信息。
关于java - 当序列化策略更改时,GWT 客户端未收到 IncompleteRemoteServiceException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9232987/