【问题标题】:GWT SerializationException, but only when marathon-LB is involvedGWT SerializationException,但仅在涉及 marathon-LB 时
【发布时间】:2018-02-01 19:34:26
【问题描述】:

我有一个运行良好的GWT webapp -- 除非我把它放在Marathon-LB 负载平衡器后面并使用HTTPS

失败发生在 POST 前后。

  • 当 webapp 不在Marathon-LB 后面时,POST 会得到 200 OK。
  • 但是当它在Marathon-LB后面时,会出现GWTSerializationException的内部服务器错误,并且POST会得到500错误。

对于失败的情况,tomcat的服务器日志中的stacktrace是这样的。注意线程是https-jsse-nio-8080-exec-6

01-Feb-2018 18:43:39.863 SEVERE [https-jsse-nio-8080-exec-6] org.apache.catalina.core.ApplicationContext.log Exception while dispatching incoming RPC call
com.google.gwt.user.client.rpc.SerializationException: Type 'com.company.SomeGwtSerializableClass' was not assignable to 'com.google.gwt.user.client.rpc.IsSerializ
able' and did not have a custom field serializer.For security purposes, this type will not be serialized.: instance = com.company.SomeGwtSerializableClass@6ce9a6c9
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:667)
        at com.google.gwt.user.client.rpc.impl.AbstractSerializationStreamWriter.writeObject(AbstractSerializationStreamWriter.java:130)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter$ValueWriter$8.write(ServerSerializationStreamWriter.java:153)
        at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serializeValue(ServerSerializationStreamWriter.java:587)

我怀疑问题出在运行 Marathon-LB 的 docker 容器和运行 Tomcat 为 webapp 服务的 docker 容器之间的信任证书。

关于如何调试这个有什么建议吗?例如,我如何确定 Marathon-LB 容器信任 webapp 容器?

谢谢!

【问题讨论】:

  • 在 Marathon-LB 之后,您是否通过不同的 URL 访问该应用程序?
  • 是的,网址不同。

标签: gwt mesos marathon mesosphere jsse


【解决方案1】:

负载均衡器破坏 GWT-RPC 的两种可能方式(至少):

  • 提供错误的内容:这可能在几种情况下发生,例如负载平衡器缓存了某些内容,或者其背后的服务器之一提供过时的文件,然后该客户端连接到最多日期服务器。
  • Mangle 传入调用:负载均衡器可能会通过多种方式出错或“帮助”并破坏某些内容 - 删除标头、将请求中的 moduleBaseUrl 重写为其他内容等。

无论哪种方式,大多数情况都涉及未能找到正确的序列化策略文件(编译输出中的 .gwt.rpc 文件),而这又是由 com.google.gwt.user.server.rpc.RemoteServiceServlet#loadSerializationPolicy 方法中的一些错误引起的。据我所知,所有这些错误都应该导致一些错误也被记录,尽管它可能是不同的文件。也许检查其他服务器日志文件以查看是否出现问题,或者在负载均衡器后面附加和调试该方法,并确保它在您看到的错误发生时返回实际策略。还要记住,这些策略文件是缓存的,所以错误只会发生一次,直到你重新启动服务器 webapp。

【讨论】:

    【解决方案2】:

    我认为您的问题是特定于 RPC 的。

    作为某种验证/保护的一部分,RPC 尝试在服务器端通过 getServletContext().getResourceAsStream 加载这些序列化策略

    /*
     * Check that the module path must be in the same web app as the servlet
     * itself. If you need to implement a scheme different than this, override
     * this method.
     */
    if (modulePath == null || !modulePath.startsWith(contextPath)) {
      String message = "ERROR: The module path requested, "
          + modulePath
          + ", is not in the same web application as this servlet, "
          + contextPath
          + ".  Your module may not be properly configured or your client and server code maybe out of date.";
      servlet.log(message);
    } else {
      // Strip off the context path from the module base URL. It should be a
      // strict prefix.
      String contextRelativePath = modulePath.substring(contextPath.length());
    
      String serializationPolicyFilePath = SerializationPolicyLoader.getSerializationPolicyFileName(contextRelativePath
          + strongName);
    
      // Open the RPC resource file and read its contents.
      InputStream is = servlet.getServletContext().getResourceAsStream(
          serializationPolicyFilePath);
    

    你可以在这里看到这个:

    https://github.com/stephenh/gwt/blob/master/user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java

    上面的问题是serializationPolicyFilePath是基于client-side路径构建的。因此,如果您的客户端路径和服务器路径不同,您将遇到麻烦。

    我在这方面遇到了很多麻烦,最后我通过RemoteServiceServlet 覆盖了一些东西,以便能够从不同的位置加载策略文件。

    Edit1:添加了缺少的额外代码行;还忘了提到问题可能出在getResourcesAsStream 调用中,或者在!modulePath.startsWith(contextPath) 比较中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 1970-01-01
      • 1970-01-01
      • 2016-12-27
      相关资源
      最近更新 更多