HTTPServletRequest中的SOAP请求主体(XML)始终为空(JAVA)

时间:2016-07-15 08:54:09

标签: java servlets soap request ejb

我知道在StackOverflow上已经多次发布了类似的问题,但在我的情况下,所有答案都没有帮助。

目标:我需要先将SOAP-Request XML记录到数据库中,然后再进行处理。
对于这个讨论,如果我能把它作为一个字符串并将其记录到控制台,我很高兴。

问题:请求XML始终为空。

环境: IBM WebSphere Application Server v8.5,EJB 3.1 Web服务(会话bean)

我实际上使用 javax.xml.soap.SOAPBody SOAPMessage 生成了一个有效的解决方案,但是在生产中似乎有另一个组件会导致以下JAX-WS冲突:

ERROR org.apache.axis2.engine.AxisEngine receive - com.sun.xml.messaging.saaj.soap.ver1_1.Body1_1Impl incompatible with com.ibm.ws.webservices.engine.xmlsoap.SOAPBody

是的,StackOverflow和IBM在改变ClassLoader策略方面有多种解决方法,比如“本地类加载器优先(父级最后一个)”,但我们目前不能这样做。
因此,我当前的方法(正在处理不同的servlet)是获取 HTTPServletRequest ,得到它的 InputStream 并使用 IOUtils.toString将其转换为String ()即可。

我知道请求只能被使用一次,我找到了几种方法来避免它(比如使用 HTTPServletRequestWrapper ),但即使使用这些变通办法,请求XML也总是空的。
最终我想在适配器中进行日志记录,但出于测试原因,我还将我的尝试放入服务本身(它没有任何效果)。

奇怪的是:我可以从请求中读取所有标题属性(使用 request.getHeader() request.getAttribute()!只有正文本身是空白的!

我正在使用 SoapUI 测试应用程序 Request-XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ping="http://services.axonactive.com/wsdl/cet/pingservice-v1.0">
  <soapenv:Header/>
  <soapenv:Body>
    <ping:PingPingIn/>
  </soapenv:Body>
</soapenv:Envelope>

响应实际上是无关紧要的,但正确工作。

控制台输出:

[ch.zek.ecls.EclsPingServiceImpl]: Initialization successful.
EclsPingServiceImpl ping - start ping()...
EclsPingServiceImpl ping - Body: 
EclsPingServiceImpl ping - body2: 
EclsUtil printRequestData - [H] Accept-Encoding: gzip,deflate
EclsUtil printRequestData - [H] Content-Type: text/xml;charset=UTF-8
EclsUtil printRequestData - [H] SOAPAction: ""
EclsUtil printRequestData - [H] Content-Length: 254
EclsUtil printRequestData - [H] Host: localhost:9443
EclsUtil printRequestData - [H] Connection: Keep-Alive
EclsUtil printRequestData - [H] User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
EclsUtil printRequestData - [A] javax.servlet.request.key_size: 128
EclsUtil printRequestData - [A] javax.servlet.request.cipher_suite: SSL_RSA_WITH_AES_128_CBC_SHA
EclsUtil printRequestData - [A] com.ibm.websphere.servlet.uri_non_decoded: /NewZekEclsHTTPRouter/PingService
EclsPingServiceImpl ping - end ping()

修改:请注意内容类型内容长度的标题[H]:
他们“知道”内容 - 如果我在请求XML中添加更多字符,那么Content-Length会相应更新 所以我得出结论,内容不会丢失,但不知何故无法访问....

web服务:

public class EclsPingServiceImpl{

@javax.annotation.Resource
WebServiceContext wsContext;

@javax.annotation.Resource
SessionContext sessionContext;

private Log log = LogFactory.getLog(EclsPingServiceImpl.class);

public PingOut ping(PingIn parameters) throws PingEntityNotFoundException, PingPermissionException, PingSystemException {

    MessageContext messageContext = wsContext.getMessageContext();
    HttpServletRequest request = (HttpServletRequest) messageContext.get(MessageContext.SERVLET_REQUEST);

    // start Try 1
    MultiReadHttpServletRequest multiReadHttpServletRequest = new MultiReadHttpServletRequest(request);
    try {
        InputStream bodyInputStream = multiReadHttpServletRequest.getInputStream();
        String body = IOUtils.toString(bodyInputStream);
        if (log.isDebugEnabled()) {
            log.debug("Body: " + body);
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // end Try 1

    // start Try 2
    try {
        InputStream body2 = request.getInputStream();
        String xml = IOUtils.toString(body2, "UTF-8");
        if (log.isDebugEnabled()) {
            log.debug("body2: " + xml);
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    // end Try 2

    // Get Header data:
    Enumeration<String> headerNames = request.getHeaderNames();
    while(headerNames.hasMoreElements()) {
        String headerName = headerNames.nextElement();
        if (log.isDebugEnabled()) {
            log.debug("[H] " + headerName + ": " + request.getHeader(headerName));
        }
    }

    // Get Attribute data:
    Enumeration<String> attributeNames = request.getAttributeNames();
    while(attributeNames.hasMoreElements()) {
        String attributeName = attributeNames.nextElement();
        if (log.isDebugEnabled()) {
            log.debug("[A] " + attributeName + ": " + request.getAttribute(attributeName));
        }
    }

    PingOut pingOut = new PingOut();
    // some irrelevant stuff...

    return pingOut;
}

}

MultiReadHttpServletRequestWrapper:
从StackOverflow复制:Http Servlet request lose params from POST body after read it once

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
    private ByteArrayOutputStream cachedBytes;

    public MultiReadHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null)
            cacheInputStream();

        return new CachedServletInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException{
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    private void cacheInputStream() throws IOException {
        /* Cache the inputstream in order to read it multiple times. For
         * convenience, I use apache.commons IOUtils
         */
        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
    }

    /* An inputstream which reads the cached request body */
    public class CachedServletInputStream extends ServletInputStream {
        private ByteArrayInputStream input;

        public CachedServletInputStream() {
            /* create a new input stream from the cached request body */
            input = new ByteArrayInputStream(cachedBytes.toByteArray());
        }

        @Override
        public int read() throws IOException {
            return input.read();
        }
    }
}

LogHandler - 只是为了显示我尝试的内容......:

public class EclsSimpleLogHandler implements javax.xml.ws.handler.soap.SOAPHandler 
{
    private Log log = LogFactory.getLog(EclsSimpleLogHandler.class);

    @Override
    public boolean handleMessage(MessageContext context) {
        boolean success = false;

        if (log.isDebugEnabled()) {
            log.debug("handleMessage()...");
        }
        Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        // check if handler is called for inbound (request) or outbound (response) message
        if (outboundProperty.booleanValue()) {
            success = handleResponse(context);
        } else {
            //success = handleRequest(context);
            success = true;
        }
        return success;
    }

    private boolean handleRequest(MessageContext messageContext) {

        if(log.isDebugEnabled()) {
            log.debug("handling request (inbound)");
        }

        // Initially logging planned here, moved out for testing reasons
        boolean success = false;

        return success;     
    }

    private boolean handleResponse(MessageContext messageContext) {

        if(log.isDebugEnabled()) {
            log.debug("handling response (outbound)");
        }

        boolean success = false;
        ByteArrayOutputStream outputStream = null;

        SOAPMessageContext context = (SOAPMessageContext) messageContext;
        SOAPMessage soapMessage = (SOAPMessage) context.getMessage();

        try {
            /*
            Initial solution, but sometimes causing:
            ERROR org.apache.axis2.engine.AxisEngine receive - com.sun.xml.messaging.saaj.soap.ver1_1.Body1_1Impl 
            incompatible with com.ibm.ws.webservices.engine.xmlsoap.SOAPBody

            // SOAPBody soapBody = soapMessage.getSOAPBody();
            // String soapBodyXml = soapBody.toString();
            */

            // This is working - but I want to avoid using SOAPMessage:
            outputStream = new ByteArrayOutputStream();
            soapMessage.writeTo(outputStream);
            String soapBodyXml = new String(outputStream.toByteArray(), "UTF-8");

            if (log.isDebugEnabled()) {
                log.debug("responseXml:\n" + soapBodyXml);
            }

            success = true;

        } catch (SOAPException e) {
            if (log.isErrorEnabled()) {
                log.error("Error while accessing SOAPMessage: " + e.getMessage());
            }
        } catch (IOException e) {
            if (log.isErrorEnabled()) {
                log.error("IOException for soapMessage.writeTo(): " + e.getMessage());
            }
            e.printStackTrace();
        }
        return success;     
    }

    // Another method, but also resulting in an empty body:
    static String extractPostRequestBody(HttpServletRequest request) {
        if ("POST".equalsIgnoreCase(request.getMethod())) {
            Scanner s = null;
            try {
                s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return s.hasNext() ? s.next() : "";
        }
        return "";
    }

    // Another method, but also resulting in an empty body:
    private String getRequestBody(HttpServletRequest request) {

        HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request);
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader = null;
        try {
            InputStream inputStream = requestWrapper.getInputStream();
            if (inputStream != null) {
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            }
        } catch (IOException ex) {
            log.error("Error reading the request payload", ex);
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException iox) {
                    // ignore
                }
            }
        }

        return stringBuilder.toString();
    }
}

0 个答案:

没有答案