Tracing XML request/responses with JAX-WS when error occurs

后端 未结 8 1873
独厮守ぢ
独厮守ぢ 2020-12-01 03:17

I want to log raw soap post requests if there are any errors , I am using JAX-WS. Any help will be appreciated.

Is there an easy way (aka: not using a proxy) to get

相关标签:
8条回答
  • 2020-12-01 03:20

    In addition to Torsten's answer

    com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true

    Make sure that you set this before instantiating the WebServiceClient object (the one that extends Service)

    0 讨论(0)
  • 2020-12-01 03:21

    Just thought I would mention this:

    The question when to use the property name with the internal in it and when not ?

    If you read the Metro Guide it will tell you to use:

    on client:

    com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
    

    on server:

    com.sun.xml.ws.transport.http.HttpAdapter.dump=true
    

    However: It seems to me that when JAX-WS RI library got included as standard with the JDK (this was with Java 6) then Sun had to rename the property name to include 'internal'. So if you are using JAX-WS RI as it comes bundled with the JDK, then you must be sure to add the internal to the property name. Otherwise it will not work. In other words you need to use:

    on client:

    com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true
    

    on server:

    com.sun.xml.internal.ws.transport.http.HttpAdapter.dump=true
    

    On the other hand if you are using a standalone version of JAX-WS RI (or of Metro as a whole) then I would guess you should use the property name without the internal.

    I'll be glad if someone has inside knowledge on this and can say if this is true or not.

    0 讨论(0)
  • 2020-12-01 03:21

    The first thing you might want to try is using one, or both, of the following system properties:

    Client:

    com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
    

    Server:

    com.sun.xml.ws.transport.http.HttpAdapter.dump=true
    
    0 讨论(0)
  • 2020-12-01 03:21

    I think that what you need is an handler, see: http://jax-ws.java.net/articles/handlers_introduction.html
    With handler you can intercept web service call, and have access to all the SOAP message.

    0 讨论(0)
  • 2020-12-01 03:30

    It is OK to go with system properties (here is Gradle DSL for test task):

    systemProperty "com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true"
    systemProperty "com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true"
    systemProperty "com.sun.xml.ws.transport.http.HttpAdapter.dump", "true"
    systemProperty "com.sun.xml.internal.ws.transport.http.HttpAdapter.dump", "true"
    systemProperty "com.sun.xml.ws.transport.http.HttpAdapter.dumpTreshold", "99999"
    systemProperty "com.sun.xml.internal.ws.transport.http.HttpAdapter.dumpTreshold", "99999"
    

    but those settings are global and may have high volume to enable them on PROD... It is not fun to add filters to your logging framework bound to business logic if you want to reduce volume of XML logging.

    Details on capturing req/rsp bodies in WS handlers are in my answer How can I pass data back from a SOAP handler to a webservice client?

    Here is an important part:

    public class MsgLogger implements SOAPHandler<SOAPMessageContext> {
    
        public static String REQEST_BODY = "com.evil.request";
        public static String RESPONSE_BODY = "com.evil.response";
    
        @Override
        public Set<QName> getHeaders() {
            return null;
        }
    
        @Override
        public boolean handleMessage(SOAPMessageContext context) {
            SOAPMessage msg = context.getMessage();
            Boolean beforeRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream(32_000);
                context.getMessage().writeTo(baos);
                String key = beforeRequest ? REQEST_BODY : RESPONSE_BODY;
                context.put(key, baos.toString("UTF-8"));
                context.setScope(key, MessageContext.Scope.APPLICATION);
            } catch (SOAPException | IOException e) { }
            return true;
        }
    
        @Override
        public boolean handleFault(SOAPMessageContext context) {
            return handleMessage(context);
        }
    
        @Override
        public void close(MessageContext context) { }
    }
    

    To register handler and use preserved properties:

    BindingProvider provider = (BindingProvider) port;
    List<Handler> handlerChain = provider.getBinding().getHandlerChain();
    handlerChain.add(new MsgLogger());
    provider.getBinding().setHandlerChain(handlerChain);
    
    Req req = ...;
    Rsp rsp = port.serviceCall(req); // call WS Port
    
    // Access saved message bodies:
    Map<String, Object> responseContext = provider.getResponseContext();
    String reqBody = (String) responseContext.get(MsgLogger.REQEST_BODY);
    String rspBody = (String) responseContext.get(MsgLogger.RESPONSE_BODY);
    

    With this solution (it is only the skeleton, proper error handling / edge cases is up to you) you decide to log later when you've got response.

    0 讨论(0)
  • 2020-12-01 03:38

    This worked for me:

    -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
    
    0 讨论(0)
提交回复
热议问题