我尝试使用 Mtom 传输文件,它工作得很好,直到我使用 SoapHandler 验证客户端签名。 SoapHandler 保留所有消息并将其更改为 base64 编码。因此,当我尝试获取大文件时,Jvm 会抛出堆大小异常。你们知道有什么方法可以解决这个问题吗?
Java JRE 附带 JAX-WS 提供程序。 我认为这个提供商有一个错误。 如果通过直接获取 HandlerChain 或使用 HandlerResolver 添加 SoapHandler,则会解构使用 MTOM 正确创建的消息,并将附件内联放置在 SOAP 消息中。 如果附件很大,可能会导致性能非常差或内存不足错误。
我找到的唯一解决方案是使用另一个 JAX-WS 提供程序。 从测试来看,Axis2 似乎工作得很好(尽管它有大量的依赖项)。 只需将另一个提供程序放在类路径上就会导致它被使用。 Java 在 META-INF/services 中查找名为 javax.xml.ws.spi.Provider 的文件。 如果找到该文件,它将使用指定的提供程序。 主 Axis2 jar 将包含此文件以确保使用 Axis2 提供程序。 其他提供商也可能解决这个问题。
由于这种自动提供程序检测,您可能会发现您的应用程序是否存在此问题,具体取决于它运行的位置。 例如,如果您将应用程序部署到 IBM WebSphere,它已经覆盖了默认的 Provider,您将不会遇到此问题。 可能其他应用程序服务器也覆盖了默认的提供程序。 如果您能找到一份副本,IBM 还提供了一个非常好的 jar,com.ibm.jaxws.thinclient_7.0.0.jar,其中打包了 Axis2。 这只能用于独立应用程序(那些不在 WebSphere 中运行的应用程序),但它非常方便并解决了这个问题。
我知道这个答案已经很晚了,可能对你不再有用,但几天前我必须解决类似的问题(不管你信不信)。这就是我所做的,这可能也适用于您的情况:
您可以使用 MessageHandler,而不是使用“传统”SOAP 处理程序(如此处所述):
public class MyHandler implements MessageHandler<MessageHandlerContext> {
public boolean handleMessage(MessageHandlerContext mhc) {
Message m = mhc.getMessage().copy();
...
return true;
}
public boolean handleFault(MessageHandlerContext mhc) {
...
return true;
}
public void close(MessageContext messageContext) { }
public Set getHeaders() {
return null;
}
}
@Jake P 正确地指出,JAX-WS 的 Metro 实现(或 JRE 中的默认实现)中存在一个错误,该错误会内联插入附件,从而修改消息,从而禁用 MTOM。但是,如果您首先复制消息(handleMessage-Method 中的第一行),即使 SOAP 处理程序处于活动状态,MTOM 也将继续工作。这使您可以从消息中读取所需的信息。