使用GWT
,我已将服务器部署到 Tomcat 。这样可以正常工作,但是当GWT
抛出异常时,Popup会向客户端显示异常的堆栈跟踪。
在开发模式下,这很好用。在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) Unknown.com_google_gwt_http_client_Request_ $ fireOnResponseReceived__Lcom_google_gwt_http_client_Request_2Lcom_google_gwt_http_client_RequestCallback_2V(Request.java:287) Unknown.com_google_gwt_http_client_RequestBuilder $ 1_onReadyStateChange__Lcom_google_gwt_xhr_client_XMLHttpRequest_2V(RequestBuilder.java:395)Unknown.anonymous(XMLHttpRequest.java:287)
请帮忙!
答案 0 :(得分:5)
为什么?
正如Christian Kuetbach所说,这是在DevMode(你的代码在Java中执行)和prod模式(你的代码编译成JavaScript并优化,包括重命名类和方法)之间的区别。
你如何解决这个问题?
你没有。一般来说,向用户显示堆栈跟踪并不是一个好主意。更好的方法是通过将异常发送到服务器来记录异常(例如,使用java.util.logging
进行记录,同时使用SimpleRemoteLogHandler
将日志发送到服务器,在那里使用{{1}进行记录}})。
虽然可以对堆栈跟踪进行反混淆处理,但java.util.logging
servlet可以配置为自动执行此操作。
有关血腥的详细信息,请参阅http://code.google.com/p/google-web-toolkit/wiki/WebModeExceptions。
如果您不能或不想使用远程日志记录,那么您可以“手动”反混淆堆栈跟踪:查看RemoteLoggingServiceImpl
中的文件(默认位置,可以通过传递{{ 1}}到GWT编译器)对应于排列(与浏览器加载的WEB-INF/deploy
文件同名),它将告诉你-deploy
方法源自哪个Java方法。
但是你已经拥有源文件名和行号,所以你真的不需要它,对吗?
答案 1 :(得分:5)
在GWT文档中找到所有信息有点困难,需要设置去混淆的日志记录,所以这里是简短的版本:
在您的模块文件(.gwt.xml)中,添加:
<inherits name="com.google.gwt.logging.Logging"/>
<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
<set-property name="compiler.stackMode" value="emulated" />
<set-configuration-property name="compiler.emulatedStack.recordLineNumbers"
value="true" />
在客户端,使用类似
的内容import java.util.logging.Logger;
private static Logger rootLogger = Logger.getLogger("");
...
rootLogger.log(Level.SEVERE, "My message", e);
您不必在客户端创建RemoteLoggingServiceAsync
实例 - 它由记录器自动使用,因为我们指定了<set-property name="gwt.logging.simpleRemoteHandler" value="ENABLED" />
。
在服务器端,配置RemoteLoggingServiceImpl。您必须告诉它,它在哪里找到symbolMaps,它将在使用GWT编译器参数-extra /path/to/myExtraDir
进行编译时生成。我个人使用这种方法来覆盖RemoteLoggingServiceImpl,允许从web.xml的<init-param>
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
中,将其注册为
<servlet>
<servlet-name>remoteLogging</servlet-name>
<servlet-class>mypackage.server.ConfigurableRemoteLoggingServiceImpl</servlet-class>
<init-param>
<param-name>symbolMapsDirectory</param-name>
<param-value>/path/to/myExtraDir/mymodulename/symbolMaps</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>remoteLogging</servlet-name>
<url-pattern>/mymodulename/remote_logging</url-pattern>
</servlet-mapping>
将/path/to/myExtraDir
,mymodulename
和mypackage
替换为您自己的值,并且不要忘记使用-extra
argument调用GWT编译器(请注意,您不要'必须使用-style PRETTY
或DETAILED,它也适用于OBF)。保留所有生成的symbolMaps:如果没有它们,则反混淆将无效。由于每个新版本都会自动获得一个唯一的名称,因此您可以在构建时将它们全部收集在安全的中心位置。
[*]我真的非常想知道为什么RemoteLoggingServiceImpl本身没有实现它!
答案 2 :(得分:1)
这可以按预期工作,因为optimaziation将删除方法和类名。
您可以编译为PRETTY或DETAILED,以获得更好的可读性Stacktraces。
还可以模拟Stacktraces。
<set-property name="compiler.emulatedStack" value="true"/>
<set-configuration-property name="compiler.emulatedStack.recordLineNumbers" value="true"/>
<set-configuration-property name="compiler.emulatedStack.recordFileNames" value="true"/>
这对于生产使用来说是个坏主意,因为它会增加你的javascript的大小。
<强>更新强> 我看到了Exception_FieldSerializer异常。
您是否尝试序列化某些不可序列化的内容?
没有默认构造函数的类不可序列化,不在客户端或共享包中的类。如果您尝试序列化异常,则可能是问题所在。