简体   繁体   中英

JAX-WS Netbeans how to enable compression web service client

I used the Web Service Client wizard in Netbeans 7.1.2, however when I try to call one the methods i receive the following error:

javax.xml.ws.soap.SOAPFaultException: Exception: Compression is Not Enabled,This Web Service expects clients to support GZIP,Deflate Compression

The generated skeleton files are numerous and I am unable to work out how to enable compression. Can anyone please advise?

Many thanks

There are four things to consider here. There's a request and a response and there's a client and server . When talking about compression it is important to be precise as to which of these cases we are targeting. I read the poster's question as being about the client side of things as it seems the server is already doing compression. (in fact it seems it mandates the client to be able to handle compression).

Here's a little background: Compression hints is a standard part of the HTTP protocol. The client will indicate to the server that it is willing to accept a compressed response by sending appropriate HTTP headers with the request. Equally the server will indicate if it has sent a compressed response by an appropriate HTTP header element in the response. The client can also send a compressed request.

These are the relevant HTTP headers elements:

  • Content-encoding : If this is set it means "I'm sending you an encoded (eg compressed) message". Both the client can use this (on the request) and well as the server (on the response).

  • Accept-encoding : If this is set it means "I can understand these types of encodings (eg compression methods), so feel free to send me data which is encoded in that format".

The typical value of these two header elements are "gzip" which is by far the most common compression method used by HTTP servers and HTTP clients. There's also "deflate" but stick with "gzip".

Let's start from the beginning: The request from the client to the server.:

It is actually quite rare to see this compressed. The reason is that the client cannot know in advance if the server can understand a compressed request. So it is generally best not to attempt this. Typically this is not a problem as it is most often the response that is big. If it is absolutely necessary to compress the request then you would need to first somehow query the server for its capabilities or be absolutely sure that it can handle a compressed request.

Then to the more interesting part: the response from the server to the client.

First of all the client needs to tell the server that he's willing to accept a compressed response. This is done on the request (duh!). The general method of how to add a HTTP header element to a JAX-WS outbound request is explained in the Metro guide here . So you would do like this:

SomeWebService someWS = service.getMyWebServicePort();
((BindingProvider)someWS).getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,
    Collections.singletonMap("Accept-Encoding",Collections.singletonList("gzip")));

You might say: "Won't this replace all of the HTTP header elements and replace it with a single element header?". Technically true but at this point JAX-WS hasn't yet added any HTTP header. JAX-WS will add its own header elements later. If you monitor the HTTP header that the server receives you'll now see something like this:

content-type : text/xml;charset="utf-8"
accept-encoding : gzip
soapaction : "http://blahblah"
accept : text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
user-agent : JAX-WS RI 2.1.5-hudson-$BUILD_NUMBER-
host : localhost:8084
connection : keep-alive
content-length : 216

The "accept-encoding" element wouldn't have been there without our explicit action. (good question why JAX-WS doesn't add this by default ??)

Now you're done with the client side. The previous poster has explained how to add compression ability on the server-side. What is relevant to note is that compression on the server-side (as long as we talk about compressing the response ) is handled solely by the container, eg by Tomcat, Glassfish, JBoss, etc, and not by your code. You just need to flip a switch in the container's configuration.

Almost done. The server is now free to send your client a gzip compressed response but at the sole discretion of the server. The server may do it or not. You don't know this.

Your final question should be: "How do I in my JAX-WS client handle a compressed response?" or more broadly "how would my JAX-WS client cope with compressed vs uncompressed responses?". The good news is that this is handled transparently by JAX-WS. There's nothing you need to do. JAX-WS will automatically detect that it receives a compressed response from the server (it simply looks at the HTTP headers in the response) and it will automatically decompress it for you. Voila!

So, dear poster, I would say that most likely, if you are using a recent version of JAX-WS, your client will already now how to handle a compressed response. However since the client hasn't explicitly told the server that it can understand a compressed response the server assumes this not to be the case and hence gives you that error. That is my guess to what you are seeing.

Ohh, and one more thing. HTTP Header element names (they are rightfully called "header fields") are case-insensitive as per RFC 2616. So you see this spelled in lots of different ways in different postings.

You can enable compression better from the application server configuration. From your question, you're most likely using glassfish or tomcat(I'm more of a tomcat person). For glassfish, you can enable compression by adding the following to your domain.xml

         <property name="compression" value="on"/>

Or if you're managing your server via the admin console, use this visual guide . For tomcat add

         compression="on" 

to your tomcat <Connector/> element in the server.xml config file.

To actually send a compressed JAX-WS request, simply indicate your intention to send a compressed request by adding the compression header to your HTTP payload

    Map<String, List<String> theHeaders = new HashMap<String, List<String>>();
theHeaders.put("Content-Encoding", Collections.singletonList("gzip"));//this indicates you're sending a compressed request
theHeaders.put("Accept-Encoding", Collections.singletonList("gzip")); //this says you're willing to accept a compressed response
Map<String, Object> reqContext = ((bindingProvider) proxy)
        .getRequestContext(); //get access to the request context of your webservice request
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpHeaders);

The above logic is better performed from a webservice handler as a matter of design

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM