为什么Tomcat无法显示实际的堆栈跟踪?

使用GWT ,我已将我的服务器部署到Tomcat中 。 这样可以正常工作,但是当GWT抛出exception时,Popup会向客户端显示exception的堆栈跟踪。

在开发模式下,这很好用。 在Tomcat中,我得到了下面的堆栈跟踪。

为什么以及如何解决这个问题?

 Unknown.Le(StackTraceCreator.java:168) Unknown.Jd(StackTraceCreator.java:421) Unknown.NT(Exception_FieldSerializer.java:16) Unknown.g1(SerializerBase.java:55) Unknown.b1(SerializerBase.java:112) Unknown.D$(AbstractSerializationStreamReader.java:119) Unknown.uAc(CustomException_FieldSerializer.java:39) Unknown.uBc(ServerSideException_FieldSerializer.java:12) Unknown.f1(SerializerBase.java:46) Unknown._0(SerializerBase.java:92) Unknown.D$(AbstractSerializationStreamReader.java:119) Unknown.B_(RequestCallbackAdapter.java:216) Unknown._o(Request.java:287) 

在使用@Christian Kuetbach的回答之后,我现在得到的是:

Unknown.com_google_gwt_core_client_impl_StackTraceCreator $ CollectorEmulated_ $ fillInStackTrace__Lcom_google_gwt_core_client_impl_StackTraceCreator $ CollectorEmulated_2Ljava_lang_Throwable_2V(StackTraceCreator.java:168)Unknown.java_lang_Throwable_Throwable__Ljava_lang_String_2Ljava_lang_Throwable_2V(StackTraceCreator.java:421)Unknown.com_google_gwt_user_client_rpc_StatusCodeException_StatusCodeException__ILjava_lang_String_2V(StatusCodeException.java:35)Unknown.com_google_gwt_user_client_rpc_impl_RequestCallbackAdapter_ $ onResponseReceived__Lcom_google_gwt_user_client_rpc_impl_RequestCallbackAdapter_2Lcom_google_gwt_http_client_Request_2Lcom_google_gwt_http_client_Response_2V(RequestCallbackAdapter.java:209)未知。 com_google_gwt_http_client_Request_ $ fireOnResponseReceived__Lcom_google_gwt_http_client_Request_2Lcom_google_gwt_http_client_RequestCallback_2V(Request.java:287)Unknown.net_google_gwt_http_client_RequestBuilder $ 1_onReadyStateChange__Lcom_google_gwt_xhr_client_XMLHttpRequest _2V(RequestBuilder.java:395)Unknown.anonymous(XMLHttpRequest.java:287)

请帮忙!

在GWT文档中找到所有信息有点困难,需要设置去混淆的日志记录,所以这里是简短的版本:

在模块文件(.gwt.xml)中,添加:

     

在客户端,使用类似的东西

 import java.util.logging.Logger; private static Logger rootLogger = Logger.getLogger(""); ... rootLogger.log(Level.SEVERE, "My message", e); 

您不必在客户端创建RemoteLoggingServiceAsync实例 – 它由记录器自动使用,因为我们指定了

在服务器端,配置RemoteLoggingServiceImpl。 您必须告诉它,它在哪里找到symbolMaps,它将在使用GWT编译器参数-extra /path/to/myExtraDir编译时生成。 我个人使用这种方法来覆盖RemoteLoggingServiceImpl,允许从web.xml的 s [*]指定目录

 package mypackage.server; public class ConfigurableRemoteLoggingServiceImpl extends RemoteLoggingServiceImpl { @Override public void init(final ServletConfig config) throws ServletException { super.init(config); final String symbolMapsDirectory = config.getInitParameter("symbolMapsDirectory"); setSymbolMapsDirectory(symbolMapsDirectory); } } 

web.xml ,将其注册为

  remoteLogging mypackage.server.ConfigurableRemoteLoggingServiceImpl  symbolMapsDirectory /path/to/myExtraDir/mymodulename/symbolMaps    remoteLogging /mymodulename/remote_logging  

用你自己的值替换/path/to/myExtraDirmymodulenamemypackage ,不要忘记用-extra参数调用GWT编译器(注意你不必使用-style PRETTY或DETAILED,它也是适用于OBF)。 保留所有生成的symbolMaps:如果没有它们,则反混淆将无效。 由于每个新版本都会自动获得一个唯一的名称,因此您可以在构建时将它们全部收集在安全的中心位置。

[*]我真的非常想知道为什么RemoteLoggingServiceImpl本身并没有实现它!

为什么?

正如Christian Kuetbach所说,这是在DevMode(你的代码在Java中执行)和prod模式(你的代码已经编译成JavaScript并进行优化,包括重命名类和方法)之间的区别。

你是如何解决这个问题的?

你没有。 一般来说,向用户显示堆栈跟踪并不是一个好主意。 更好的方法是通过将exception发送到服务器来记录exception(例如,使用java.util.logging进行记录,以及SimpleRemoteLogHandler将日志发送到服务器,在那里使用java.util.logging记录它)。

有一些方法可以对堆栈跟踪进行反混淆处理,并且RemoteLoggingServiceImpl servlet可以配置为自动执行。
有关详细信息,请参阅http://code.google.com/p/google-web-toolkit/wiki/WebModeExceptions 。

如果您不能或不想使用远程日志记录,那么您可以“手动”反混淆堆栈跟踪:查看WEB-INF/deploy中的文件(默认位置,可以通过将-deploy传递给GWT来更改)编译器)与排列相对应(与浏览器加载的*.cache.*文件*.cache.* ),它会告诉你Le方法源自哪种Java方法。
但是你已经拥有源文件名和行号,所以你真的不需要它,对吧?

这可以按预期工作,因为optimaziation将删除方法和类名。

您可以编译为PRETTY或DETAILED,以获得更好的可读Stacktraces。

还可以模拟Stacktraces。

    

这对于生产使用来说是个坏主意,因为它会增加你的javascript的大小。

更新:我看到Exception_FieldSerializerexception。

你试图序列化一些不可序列化的东西吗?

没有默认构造函数的类不可序列化,不在客户端或共享包中的类。 如果您尝试序列化exception,则可能是问题所在。