Saturday March 10, 2018
In this article I'll be demonstrating two ways to compress Apache CXF SOAP requests and responses to conserve network resources--Fast Infoset (FI) and GZip compression. We'll modify the introductory DoubleIt web service tutorial to test this functionality along with Wireshark to see how the SOAP requests and responses change as a result. The code modifications necessary are quite minimal, just a few lines over one or two source files.
As a reference point, let's use Wireshark to see the SOAP request and response for a standard DoubleIt call without compression:
POST /doubleit/services/doubleit HTTP/1.1
Content-Type: text/xml; charset=UTF-8
Accept: */*
SOAPAction: ""
User-Agent: Apache-CXF/3.2.2
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8080
Connection: keep-alive
Content-Length: 224
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt">
<numberToDouble>10</numberToDouble>
</ns2:DoubleIt>
</soap:Body>
</soap:Envelope>
HTTP/1.1 200
Content-Type: text/xml;charset=UTF-8
Content-Length: 238
Date: Sat, 10 Mar 2018 16:09:14 GMT
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DoubleItResponse xmlns:ns2="http://www.example.org/schema/DoubleIt">
<doubledNumber>20</doubledNumber>
</ns2:DoubleItResponse>
</soap:Body>
</soap:Envelope>
First, let's activate fast infoset, both client- and service-side. The negotiation process involves the SOAP client sending an uncompressed Accept: application/fastinfoset HTTP header in the first SOAP request. If the server is configured to support FI, it will return a compressed SOAP response with a content type of application/fastinfoset. Subsequently all SOAP requests and responses between the client and web service provider will then use FI. However, if the server is not configured to use FI the server will return an uncompressed SOAP response with the usual text/xml Content-Type. The following table shows how to activate FI:
| Component | How to implement Fast Infoset Compression |
|---|---|
| CXF Web Service Provider |
Add the FastInfoset dependency to your project. Then attach the @FastInfoset feature to either the Service Endpoint Interface (SEI) or SEI implementation:
@WebService(targetNamespace = "http://www.example.org/contract/DoubleIt"...
@org.apache.cxf.annotations.FastInfoset
public class DoubleItPortTypeImpl implements DoubleItPortType {
....
}
Alternative configuration options: Can configure via the org.apache.cxf.feature.FastInfosetFeature either on the ServerFactoryBean or the cxf:bus. As the FastInfosetFeature just installs the two FI interceptors, those interceptors can also be added programmatically to the web service endpoint. Note FI will be activated only if the client requests it. The feature's |
| CXF SOAP Client |
Add the FastInfoset dependency to your project. Then add the FastInfoset interceptors to the SOAP client class:
public class WSClient {
public static void main (String[] args) {
DoubleItService service = new DoubleItService();
DoubleItPortType port = service.getDoubleItPort();
Client client = ClientProxy.getClient(port);
client.getInInterceptors().add(new org.apache.cxf.interceptor.FIStaxInInterceptor());
client.getOutInterceptors().add(new org.apache.cxf.interceptor.FIStaxOutInterceptor());
...
}
}
Alternative: add the FastInfosetFeature to the ClientFactoryBean. Note FI will be activated only if the service is configured to provide it. FI can be forced from the client to the service without negotiation using the methods described above for the web service provider, however there is no guarantee the service provider will be able to process it. |
Now, let's check the results over the wire:
POST /doubleit/services/doubleit HTTP/1.1
Content-Type: text/xml; charset=UTF-8
Accept: application/fastinfoset, */*
SOAPAction: ""
User-Agent: Apache-CXF/3.2.2
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8080
Connection: keep-alive
Content-Length: 224
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt">
<numberToDouble>10</numberToDouble>
</ns2:DoubleIt>
</soap:Body>
</soap:Envelope>
HTTP/1.1 200
Content-Type: application/fastinfoset
Transfer-Encoding: chunked
Date: Sat, 10 Mar 2018 17:39:16 GMT
.....8..soap(http://schemas.xmlsoap.org/soap/envelope/.?...Envelope?...Body8..ns2%http://www.example.org/schema/DoubleIt.?...DoubleItResponse<.doubledNumber.20....POST /doubleit/services/doubleit HTTP/1.1
Content-Type: application/fastinfoset
Accept: application/fastinfoset, */*
SOAPAction: ""
User-Agent: Apache-CXF/3.2.2
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8080
Connection: keep-alive
Content-Length: 155
.....8..soap(http://schemas.xmlsoap.org/soap/envelope/.?...Envelope?...Body8..ns2%http://www.example.org/schema/DoubleIt.?...DoubleIt<
numberToDouble.0....HTTP/1.1 200
Content-Type: application/fastinfoset
Transfer-Encoding: chunked
Date: Sat, 10 Mar 2018 17:39:16 GMT
.....8..soap(http://schemas.xmlsoap.org/soap/envelope/.?...Envelope?...Body8..ns2%http://www.example.org/schema/DoubleIt.?...DoubleItResponse<.doubledNumber.0....
For GZIP, follow the below table for configuration information. The negotiation process involves the SOAP client sending an Accept-Encoding: gzip HTTP header in the first SOAP request. If the server is configured to support GZIP compression, it will return a compressed SOAP response with the Content-Encoding: gzip HTTP Header. Subsequently all SOAP requests and responses between the client and web service provider will then use GZIP. If the server is not configured to use GZIP then SOAP requests and responses will be sent as normal, uncompressed.
| Component | How to implement GZIP Compression |
|---|---|
| CXF Web Service Provider | Attach the @org.apache.cxf.annotations.GZIP annotation to DoubleItPortTypeImpl, or either the GZIPFeature or its two corresponding interceptors as described in the previous table for the FI configuration. Note the annotation, feature and GZIPOutInterceptor all provide an optional |
| CXF SOAP Client | Attach the GZIPFeature or the GZIP interceptors (along with the threshold value, if desired) as described in the previous table for FI. |
The results with GZIP are shown below. I set the threshold to zero, both client- and service-side, to ensure compression of all messages. (Note following Wireshark's HTTP stream will uncompress by default, causing one to think no compression is occurring. To see the compressed values as below, right-click any packet part of the SOAP calls and choose "Follow->TCPStream" instead.)
POST /doubleit/services/doubleit HTTP/1.1
Content-Type: text/xml; charset=UTF-8
Accept: */*
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
SOAPAction: ""
User-Agent: Apache-CXF/3.2.2
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8080
Connection: keep-alive
Content-Length: 224
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt">
<numberToDouble>10</numberToDouble>
</ns2:DoubleIt>
</soap:Body>
</soap:Envelope>HTTP/1.1 200
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Type: text/xml;charset=UTF-8
Content-Length: 158
Date: Sat, 10 Mar 2018 18:03:20 GMT
..........m.... .D....X.#A.F.^<..T6..,..........d&.fW1.(.aFG.w.w.e..M?.Q...GoX.........)A.U...>.
...M...xC..x....M) \.....:.k33m..:......l......s.l../&.......
POST /doubleit/services/doubleit HTTP/1.1
Content-Type: text/xml; charset=UTF-8
Accept: */*
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
Content-Encoding: gzip
SOAPAction: ""
User-Agent: Apache-CXF/3.2.2
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8080
Connection: keep-alive
Content-Length: 150
..........].1..0.E..z..1F!......`.!..:m..q..
.....l.\..8....)....c...4..;....*W.?...k..kf.../k"......5.>A_])E..B...f=|...Ch............u..?..7Y.......HTTP/1.1 200
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Type: text/xml;charset=UTF-8
Content-Length: 157
Date: Sat, 10 Mar 2018 18:03:20 GMT
..........m.... .D....X.. .../...*.{..t.......x..d..*&..)<.Q...]`Y.}7..%.....E../h.C....tZ5...S..;y..wxNW.H..n...........l3.4..6i/..q.[.kC...b........Q.7....
Posted by Glen Mazza in Web Services at 07:00AM Mar 10, 2018 | Comments[0]