【问题标题】:Apache cxf and large SOAP requestsApache cxf 和大型 SOAP 请求
【发布时间】:2020-09-24 08:29:08
【问题描述】:

我可能有一个大请求 (SOAP) 发送到应用程序服务器 wildfly 20,我想知道如何处理该请求而不将所有请求都解析在内存中。

我的问题是,在 CXF 调用 DocLiteralnInterceptor 拦截器之后,请求本身变成了内存中的完整对象。如何避免这种情况?在不破坏与 SOAP 请求相关的 cxf 预期功能的情况下删除此拦截器是否安全?

拦截器中的默认 CXF

  1. AttachmentInInterceptor
  2. StaxInInterceptor
  3. ReadHeadersInterceptor
  4. SoapActionInInterceptor
  5. 必须理解拦截器
  6. SOAPHandlerInterceptor
  7. Lo​​gicalHandlerInInterceptor
  8. CheckFaultInterceptor
  9. URIMappingInterceptor
  10. DocLiteralnInterceptor
  11. SoapHeaderInterceptor
  12. WrapperClassInInterceptor
  13. SwaInInterceptor
  14. HolderInInterceptor
  15. ServiceInvokerInInterceptor

我的第一个想法是删除从 10 到 15 的所有拦截器,并编写一个拦截器,它可以分段解析给定的请求(stax),但我不知道我将如何处理解析的块以及如何处理我同时将处理后的片段写入输出流,是否需要使用线程?我需要删除输出拦截器(会破坏 cxf)吗?

但话又说回来,拦截器仅用于预处理或后处理请求,业务逻辑应在 Web 服务方法中调用,但在这种情况下,我需要绕过 Web 服务方法并从 inInterceptor 直接转到 outInterceptor,是吗?对吧?

我的第二个想法是在 DocLiteralnInterceptor 解析一段请求(比如说 1000 个 subObject 元素)之前添加拦截器并将其包装在根(object) 元素并从 DocLiteralnInterceptor 开始的拦截器链多次调用,这种解决方案是否可行?如果是这样,我该怎么做?在这种情况下,我不需要绕过 webservice 方法。但不确定这个解决方案是否普遍可行

我的请求对象示例如下

<?xml version="1.0" encoding="UTF-8"?>
<object>
   <subObject>
      <id>12</id>
      <item>
         <id>15</id>
         <name>block</name>
         ...<- other fields
      </item>
   </subObject>
   ...<- subObject element repeated 500k (500, 000) times
</object>

【问题讨论】:

    标签: cxf


    【解决方案1】:

    不确定是否可以在没有 mtom 的情况下有效地使用 cxf 处理大型请求。

    您可以尝试使用 Provider 接口处理请求

    public class MyService implements Provider<StAXSource> {
    }
    

    但是,如果您的响应也比我怀疑提供者界面对您有帮助,因为 看来您需要返回 StAXSource,如果您的请求很大,则会消耗大量内存。

    https://docs.oracle.com/middleware/1213/wls/WSGET/jax-ws-provider.htm#WSGET656

    从上面的链接复制粘贴

    package examples.webservices.jaxws;
     
    import org.w3c.dom.Node;
     
    import javax.xml.transform.Source;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.dom.DOMResult;
    import javax.xml.transform.stream.StreamSource;
    import javax.xml.ws.Provider;
    import javax.xml.ws.ServiceMode;
    import javax.xml.ws.WebServiceProvider;
    import javax.xml.ws.Service;
    import java.io.ByteArrayInputStream;
     
     
    /**
     * A simple Provider-based web service implementation.
     *
     * @author Copyright (c) 2010, Oracle and/or its affiliates. 
     * All Rights Reserved.
     */
    // The @ServiceMode annotation specifies whether the Provider instance 
    // receives entire messages or message payloads.
    @ServiceMode(value = Service.Mode.PAYLOAD)
    
    // Standard JWS annotation that configures the Provider-based web service.
    @WebServiceProvider(portName = "SimpleClientPort",
        serviceName = "SimpleClientService",
        targetNamespace = "http://jaxws.webservices.examples/",
        wsdlLocation = "SimpleClientService.wsdl")
    public class SimpleClientProviderImpl implements Provider<Source> {
     
      //Invokes an operation according to the contents of the request message.
      public Source invoke(Source source) {
        try {
          DOMResult dom = new DOMResult();
          Transformer trans = TransformerFactory.newInstance().newTransformer();
          trans.transform(source, dom);
          Node node = dom.getNode();
          // Get the operation name node.
          Node root = node.getFirstChild();
          // Get the parameter node.
          Node first = root.getFirstChild();
          String input = first.getFirstChild().getNodeValue();
          // Get the operation name.
          String op = root.getLocalName();
          if ("invokeNoTransaction".equals(op)) {
            return sendSource(input);
          } else {
            return sendSource2(input);
          }
        }
        catch (Exception e) {
          throw new RuntimeException("Error in provider endpoint", e);
        }
      }
     
      private Source sendSource(String input) {
        String body =
            "<ns:invokeNoTransactionResponse
                 xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
                + "constructed:" + input
                + "</return></ns:invokeNoTransactionResponse>";
        Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
        return source;
      }
     
      private Source sendSource2(String input) {
        String body =
            "<ns:invokeTransactionResponse 
                xmlns:ns=\"http://jaxws.webservices.examples/\"><return>"
                + "constructed:" + input
                + "</return></ns:invokeTransactionResponse>";
        Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
        return source;
      }
     
    } 
    

    如您所见,xml 响应字符串保存在内存中。

    您也可以尝试使用 Dispatch 接口,即

    (从同一链接复制)

    package jaxws.dispatch.client;
     
    import java.io.ByteArrayOutputStream;
    import java.io.OutputStream;
    import java.io.StringReader;
    import java.net.URL;
     
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPMessage;
    import javax.xml.transform.OutputKeys;
    import javax.xml.transform.Source;
    import javax.xml.transform.Transformer;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.TransformerFactory;
    import javax.xml.transform.stream.StreamResult;
    import javax.xml.transform.stream.StreamSource;
    
    import javax.xml.ws.Dispatch;
    import javax.xml.ws.Service;
    import javax.xml.ws.WebServiceException;
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.JAXBElement;
    import javax.xml.namespace.QName;
    import javax.xml.ws.soap.SOAPBinding;
     
    public class WebTest extends TestCase {
       private static String in_str = "wiseking";
       private static String request = 
          "<ns1:sayHello xmlns:ns1=\"http://example.org\"><arg0>"+in_str+"</arg0></ns1:sayHello>";
     
       private static final QName portQName = new QName("http://example.org", "SimplePort");
       private Service service = null;
    
       protected void setUp() throws Exception {
     
          String url_str = System.getProperty("wsdl");
          URL url = new URL(url_str);
          QName serviceName = new QName("http://example.org", "SimpleImplService");
          service = Service.create(serviceName);
          service.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, url_str);
          System.out.println("Setup complete.");
     
       }
     
       public void testSayHelloSource() throws Exception {
          setUp();
          Dispatch<Source> sourceDispatch = 
             service.createDispatch(portQName, Source.class, Service.Mode.PAYLOAD);
          System.out.println("\nInvoking xml request: " + request);
          Source result = sourceDispatch.invoke(new StreamSource(new StringReader(request)));
          String xmlResult = sourceToXMLString(result);
          System.out.println("Received xml response: " + xmlResult);
          assertTrue(xmlResult.indexOf("HELLO:"+in_str)>=0);
       }
     
       private String sourceToXMLString(Source result) {
          String xmlResult = null;
          try {
             TransformerFactory factory = TransformerFactory.newInstance();
             Transformer transformer = factory.newTransformer();
             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
             OutputStream out = new ByteArrayOutputStream();
             StreamResult streamResult = new StreamResult();
             streamResult.setOutputStream(out);
             transformer.transform(result, streamResult);
             xmlResult = streamResult.getOutputStream().toString();
          } catch (TransformerException e) {
             e.printStackTrace();
          }
          return xmlResult;
       }
     
    }
    

    另一方面 你可以编写自己的 servlet 实现,它接受大型请求并逐个处理它并返回一些内容作为输出。

    但总的来说,我怀疑没有 mtom 或类似的东西可以用 cxf 处理大型请求

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-22
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      相关资源
      最近更新 更多