H2TransportSender (HTTP/2 Transport)
🚀 TL;DR - Quick Start for Large Payloads (50MB+)
Most Common Use Case: Processing 50MB+ JSON payloads with optimal performance
Production Configuration (axis2.xml) - AWS/Cloudflare Ready:
<transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"> <parameter name="PROTOCOL">HTTP/2.0</parameter> <!-- ALPN Support (Required for AWS ALB, Cloudflare); HTTPS is always enforced --> <parameter name="enableALPN">true</parameter> <parameter name="supportedProtocols">TLSv1.2,TLSv1.3</parameter> <!-- Large Payload Optimization --> <parameter name="maxConcurrentStreams">20</parameter> <parameter name="initialWindowSize">2097152</parameter> <!-- 2MB window (default 64KB) --> <!-- Timeouts --> <parameter name="connectionTimeout">30000</parameter> <!-- 30s connect --> <parameter name="responseTimeout">300000</parameter> <!-- 5min response --> <!-- HTTP/2 fallback to HTTP/1.1 is automatic via TLS ALPN --> </transportSender>
Client Access for 50MB JSON Payloads:
Most JSON clients will use curl or Apache HTTP Components directly:
# curl with HTTP/2 for large JSON payloads (AWS/Cloudflare compatible)
curl --http2-prior-knowledge -X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "User-Agent: MyApp/1.0" \
--max-time 300 --connect-timeout 30 \
--compressed \
--data @large-payload.json \
https://server:8443/services/BigDataService
# Apache HTTP Components 5.x (Java clients)
CloseableHttpAsyncClient httpClient = HttpAsyncClients.custom()
.setVersionPolicy(HttpVersionPolicy.FORCE_HTTP_2)
.build();
httpClient.start();
HttpPost request = new HttpPost("https://server:8443/services/BigDataService");
request.setEntity(new StringEntity(jsonPayload, ContentType.APPLICATION_JSON));
Expected Performance: 40-70% faster than HTTP/1.1 for 50MB+ JSON payloads with 20% less memory usage
Note: Server push is disabled by default as it's not beneficial for JSON APIs (see "Server Push Capabilities" section below for detailed explanation).
H2TransportSender provides enterprise-grade HTTP/2 transport capabilities using HttpClient 5.x with advanced features for large payload processing, connection multiplexing, and performance optimization. This transport is specifically designed for big data applications requiring 50MB+ JSON payload support with memory-efficient 64 KB flush intervals.
HTTP/2 offers significant advantages over HTTP/1.1:
- Binary protocol with header compression (HPACK)
- Stream multiplexing - multiple concurrent requests over single connection
- Server push capabilities (configurable)
- Improved flow control with window scaling
- Enhanced performance for large payloads
- Reduced connection overhead and latency
Basic HTTP/2 Configuration
The <transportSender/> element for HTTP/2 transport:
<transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"> <parameter name="PROTOCOL">HTTP/2.0</parameter> <parameter name="maxConcurrentStreams">100</parameter> <parameter name="initialWindowSize">2097152</parameter> <!-- 2MB -- see note below --> <parameter name="serverPushEnabled">false</parameter> </transportSender>
Flow-control window vs. streaming flush interval
initialWindowSize and the FlushingOutputStream 64 KB flush interval are independent settings that should not be "aligned" to the same value.
- FlushingOutputStream flush (server-side, 64 KB) — controls when serialized bytes are pushed into the HTTP/2 framing layer. 64 KB is a good cadence: it gives early time-to-first-byte and prevents reverse proxy timeouts on long-running serializations. This value is correct and should not change.
- initialWindowSize (client-side, per-stream) — controls how much data a stream may have in-flight before the sender pauses for a WINDOW_UPDATE acknowledgement from the receiver. A 10 MB response with a 64 KB window requires ~156 WINDOW_UPDATE round-trips; with a 2 MB window it requires ~5. Under concurrent load, these round-trips serialize on each TCP connection, adding significant latency.
A server flushing at 64 KB works well with a client whose window is 2 MB — the server sends 64 KB, the framing layer accumulates up to 2 MB of in-flight data, and the client acknowledges in bulk. Setting both to 64 KB forces the client to acknowledge every single flush, converting each 64 KB chunk into a synchronous round-trip.
HTTP/2 Configuration Parameters
| Parameter | Description | Default | Range |
|---|---|---|---|
| maxConcurrentStreams | Maximum concurrent streams per connection. Lower values (4-8) force the connection pool to spread streams across multiple TCP connections — better for workloads with few concurrent large payloads. Higher values (50-100) maximize multiplexing efficiency for many small concurrent requests. | 100 | 1-1000 |
| initialWindowSize | HTTP/2 per-stream flow-control window (bytes). Determines how much data can be in-flight per stream before the sender waits for a WINDOW_UPDATE. For payloads above 1 MB, use at least 1-2 MB to avoid excessive round-trips. Not related to the server-side FlushingOutputStream 64 KB flush interval. | 65536 | 64KB-16MB |
| maxConnectionsTotal | Maximum connections in the pool | 50 | |
| maxConnectionsPerRoute | Maximum connections per host | 10 | |
| serverPushEnabled | Accept HTTP/2 server push | false | |
| streamingBufferSize | Buffer size for streaming flush interval | 65536 | 8KB-1MB |
| connectionTimeout | Connection establishment timeout (ms) | 30000 | 1000-60000 |
| responseTimeout | Response timeout for large payloads (ms) | 300000 | 30000-600000 |
| connectionKeepAliveTime | Idle time before a pooled connection is closed (ms) | 300000 | |
| enableALPN | Negotiate h2 with TLS ALPN | true | |
| supportedProtocols | Enabled TLS versions | TLSv1.2,TLSv1.3 | |
| supportedCipherSuites | Enabled cipher suites | TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256 |
Tuning for Different Workloads
The optimal maxConcurrentStreams and initialWindowSize depend on your traffic pattern. With Apache HttpComponents 5.x, the PoolingAsyncClientConnectionManager only opens a new TCP connection when all existing connections have reached their maxConcurrentStreams limit. If this value is higher than your typical concurrency, the pool will multiplex all streams onto a single connection — which is efficient for many small requests but creates flow-control contention for concurrent large payloads.
| Workload | Example | maxConcurrentStreams | initialWindowSize | maxConnectionsPerRoute |
|---|---|---|---|---|
| Many small concurrent requests | Microservice mesh, API gateway | 50-100 | 2 MB | 10 |
| Few large concurrent payloads | Batch processing, ETL, report generation | 4-8 | 8 MB | 16-32 |
| Mixed traffic | General-purpose service client | 8-16 | 2 MB | 16 |
Client-side vs. server-side window: where tuning matters
HTTP/2 flow control is bidirectional — both client and server advertise an initialWindowSize. For typical Axis2 deployments where the server produces large JSON responses and the client sends smaller requests (query parameters, filter criteria), the client-side window is the critical tuning point. It governs how much response data the server can push before pausing for a WINDOW_UPDATE from the client. A 64 KB client window on a 10 MB response means ~156 pause-and-acknowledge cycles.
The server's inbound window (configured in the application server — e.g., WildFly's http2-initial-window-size, Tomcat's http2InitialWindowSize) controls how much request data the server allows in-flight. Since requests are typically small relative to responses, the server-side default (64 KB per the HTTP/2 spec) is usually adequate. Focus tuning effort on the H2TransportSender client-side initialWindowSize shown above.
If a single client consumes both small and large payload endpoints on different hosts, consider configuring separate CloseableHttpAsyncClient instances with per-workload tuning. The connection pool's maxConnectionsPerRoute already isolates traffic by host, but maxConcurrentStreams and initialWindowSize apply to the entire client.
Enterprise Big Data Configuration
For enterprise applications processing large JSON datasets (50MB+), use the following optimized configuration. Note the lower maxConcurrentStreams (forces the pool to open multiple TCP connections under concurrent load) and larger initialWindowSize (eliminates per-stream flow-control round-trips):
<transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender">
<parameter name="PROTOCOL">HTTP/2.0</parameter>
<!-- Stream Management: low stream count forces connection pooling
instead of multiplexing all large payloads onto one TCP connection -->
<parameter name="maxConcurrentStreams">4</parameter>
<parameter name="initialWindowSize">8388608</parameter> <!-- 8MB -- a 50MB payload completes in ~6 window updates -->
<!-- Large Payload Optimization -->
<parameter name="streamingBufferSize">65536</parameter>
<!-- Connection Management: sized for concurrent large-payload fan-out -->
<parameter name="maxConnectionsTotal">64</parameter>
<parameter name="maxConnectionsPerRoute">32</parameter>
<!-- Timeouts for Large Payloads -->
<parameter name="connectionTimeout">30000</parameter>
<parameter name="responseTimeout">300000</parameter>
</transportSender>
HTTPS with HTTP/2 (ALPN)
HTTP/2 over HTTPS requires Application-Layer Protocol Negotiation (ALPN). The H2TransportSender only accepts https endpoints and handles ALPN negotiation automatically (enableALPN defaults to true):
<transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"> <parameter name="PROTOCOL">HTTP/2.0</parameter> <parameter name="enableALPN">true</parameter> <parameter name="supportedProtocols">TLSv1.2,TLSv1.3</parameter> </transportSender>
Stream Multiplexing Configuration
HTTP/2 stream multiplexing allows multiple concurrent requests over a single connection, significantly improving performance for concurrent operations:
// Enable HTTP/2 multiplexing in client code: select the "h2" sender from axis2.xml
Options options = new Options();
options.setSenderTransport("h2", configContext.getAxisConfiguration());
// HTTP/2 multiplexing is automatic when using the h2 transport.
// No additional boolean flags are needed.
Large Payload Processing
The H2TransportSender provides three processing modes optimized for different payload sizes:
- Standard Processing (0MB-10MB): Regular HTTP/2 features
- Multiplexing Mode (10-50MB): Enhanced concurrent processing
- Streaming Mode (50MB+): Memory-efficient streaming with chunked processing
Streaming and memory optimization are controlled by the message formatter selected in axis2.xml (e.g. MoshiStreamingMessageFormatter). No client-side Options properties are required — the transport sender negotiates HTTP/2 framing and flow control automatically.
Performance Monitoring
For production monitoring, use Micrometer with Prometheus/Grafana or Spring Boot Actuator endpoints. Application-level logging via the Axis2 log configuration provides per-request timing details.
Available metrics include:
- Stream allocation and utilization
- Memory usage and buffer efficiency
- Processing time and throughput
- Compression ratios and bandwidth savings
- Connection reuse statistics
Flow Control
HTTP/2 flow control is handled automatically by the transport layer. The initialWindowSize parameter on the transport sender controls the initial flow-control window; beyond that, the HTTP/2 implementation manages window updates and back-pressure without additional configuration.
Compression
Response compression is handled by the servlet container (Tomcat, WildFly, etc.), not by the Axis2 transport. Configure compression in your container's server configuration (e.g., Tomcat's server.xml compression attribute, or WildFly's Undertow content-encoding filter). HTTP/2 header compression (HPACK) is always active and requires no Axis2 configuration.
Memory Management
Buffer management is handled internally by Apache HttpComponents 5.x. The JVM's default direct memory limit (equal to -Xmx) is sufficient for most deployments. No additional JVM flags are needed for HTTP/2 buffer management.
Error Handling and Fallback
When the remote server does not support HTTP/2, the TLS ALPN negotiation falls back to HTTP/1.1 automatically. No explicit fallback parameters are required — Apache HttpComponents handles protocol negotiation.
Server Push
Server push is disabled by default — REST/JSON APIs follow request-response patterns where push provides no benefit. Enable only for web-app use cases with predictable resource dependencies:
<parameter name="serverPushEnabled">false</parameter> <!-- default -->
Service-Level HTTP/2 Configuration
Individual services can specify HTTP/2 preferences in their services.xml:
HTTP/2 is enabled at the transport level in axis2.xml, not per-service. Select the H2TransportSender in the <transportSender> section and configure its parameters there. For streaming large payloads, use the streaming message formatter (e.g. MoshiStreamingMessageFormatter or JSONStreamingMessageFormatter) in the service's message receiver configuration. No service-level parameters are required.
Client-Side HTTP/2 Usage for SOAP (for JSON, see curl and Apache HTTPComponents section)
Complete client configuration example:
// Create HTTP/2 enabled service client
ConfigurationContext configContext = ConfigurationContextFactory
.createConfigurationContextFromFileSystem(null, null);
ServiceClient serviceClient = new ServiceClient(configContext, null);
// Configure HTTP/2 transport
Options options = new Options();
options.setSenderTransport("h2", configContext.getAxisConfiguration());
options.setTo(new EndpointReference("https://localhost:8443/services/BigDataService"));
// HTTP/2 is negotiated by the transport sender selected in axis2.xml.
// No additional boolean flags are needed — the h2 transport handles
// multiplexing, streaming, and flow control automatically.
// Timeout settings for large payloads
options.setTimeOutInMilliSeconds(300000); // 5 minutes
options.setProperty(HTTPConstants.CONNECTION_TIMEOUT, 30000);
options.setProperty(HTTPConstants.SO_TIMEOUT, 300000);
serviceClient.setOptions(options);
Performance Comparison: HTTP/1.1 vs HTTP/2
HTTP/2 transport can provide substantial improvements over HTTP/1.1. The following are illustrative estimates — actual results depend on payload size, network conditions, and JVM configuration:
| Metric | HTTP/1.1 | HTTP/2 | Improvement |
|---|---|---|---|
| Connection Multiplexing | 6-8 connections | 100 concurrent streams | 1,150-1,567% |
| Memory Efficiency | Standard allocation | Pooled buffers | 30-50% |
| Large Payload (50MB) | Baseline | Streaming optimization | 50-200% |
| Compression | Basic gzip | JSON-aware optimization | 50-70% |
| Overall Throughput | Baseline | Combined optimizations | 70-150% |
Troubleshooting HTTP/2
Common HTTP/2 configuration issues and solutions:
ALPN Not Available
ALPN is built into Java 17 and later, so no system property or extra library is needed. If HTTP/2 is not negotiated, check that the endpoint uses https, that the server advertises h2, and that enableALPN has not been set to false.
Memory Issues with Large Payloads
// Increase heap size for large JSON payloads -Xmx4g -XX:+UseG1GC
Connection Issues
HTTP/2 fallback to HTTP/1.1 is automatic via TLS ALPN negotiation. If the server does not advertise h2, the client falls back transparently. Increase connectionTimeout on the transport sender if ALPN negotiation is slow on your network.
Migration from HTTP/1.1 to HTTP/2
To migrate existing HTTP/1.1 configurations to HTTP/2:
- Change transport sender class to H2TransportSender
- Update protocol parameter to HTTP/2.0
- Add HTTP/2 specific parameters
- Configure HTTPS with ALPN support
- Test with fallback enabled
Example migration:
<!-- HTTP/1.1 Configuration --> <transportSender name="http" class="org.apache.axis2.transport.http.impl.httpclient5.HTTPClient5TransportSender"> <parameter name="PROTOCOL">HTTP/1.1</parameter> <parameter name="Transfer-Encoding">chunked</parameter> </transportSender> <!-- HTTP/2 Configuration --> <transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"> <parameter name="PROTOCOL">HTTP/2.0</parameter> <parameter name="maxConcurrentStreams">100</parameter> <parameter name="initialWindowSize">2097152</parameter> <!-- Fallback to HTTP/1.1 is automatic via TLS ALPN negotiation --> </transportSender>
SSL Client Authentication (2-Way SSL) with HTTP/2
HTTP/2 transport supports SSL client authentication (mutual TLS) similar to HTTP/1.1, with enhanced features for certificate management and ALPN negotiation. You can configure your own HttpAsyncClient with custom SSL context and certificate handling.
The HTTP/2 transport supports the same certificate management as HTTP/1.1 but uses async client architecture. To control max connections per host, SSL configuration, or other advanced parameters, set the cached HTTP/2 client using the CACHED_HTTP2_ASYNC_CLIENT property before making requests.
The following example shows SSL client authentication configuration tested with Axis2 on WildFly 32:
// Certificate and TrustStore setup (same as HTTP/1.1)
String wildflyserver_cert_path = "src/wildflyserver.crt";
Certificate certificate = CertificateFactory.getInstance("X.509")
.generateCertificate(new FileInputStream(new File(wildflyserver_cert_path)));
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);
TrustManagerFactory trustManagerFactory = null;
trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new Exception("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
// SSL Context with TLS 1.3 support for HTTP/2
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, trustManagers, new SecureRandom());
// HTTP/2 specific TLS strategy with ALPN support
TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
.setSslContext(sslContext)
.setHostnameVerifier(NoopHostnameVerifier.INSTANCE) // For self-signed certificates
.setTlsDetailsFactory(sslEngine -> {
// Configure ALPN protocols for HTTP/2 negotiation
SSLParameters sslParams = sslEngine.getSSLParameters();
sslParams.setApplicationProtocols(new String[]{"h2", "http/1.1"});
sslEngine.setSSLParameters(sslParams);
return null;
})
.build();
// HTTP/2 async connection manager with SSL configuration
PoolingAsyncClientConnectionManager connManager = PoolingAsyncClientConnectionManagerBuilder.create()
.setTlsStrategy(tlsStrategy)
.setMaxConnTotal(100)
.setMaxConnPerRoute(100)
.build();
// Create HTTP/2 async client with SSL configuration
CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom()
.setConnectionManager(connManager)
.setConnectionManagerShared(true)
.setVersionPolicy(HttpVersionPolicy.NEGOTIATE) // Allow HTTP/2 negotiation
.build();
httpAsyncClient.start(); // Important: Start the async client
// Configure service client with HTTP/2 SSL client
Options options = new Options();
options.setTo(new EndpointReference("https://myserver:8443/services/MyService"));
options.setSenderTransport("h2", configContext.getAxisConfiguration()); // Use HTTP/2 transport
options.setTimeOutInMilliSeconds(120000);
// Set the cached HTTP/2 async client (HTTP/2 equivalent of CACHED_HTTP_CLIENT)
options.setProperty("CACHED_HTTP2_ASYNC_CLIENT", httpAsyncClient);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
HTTP/2 SSL Configuration Parameters
The HTTP/2 transport provides additional SSL-specific parameters:
| Parameter | Description | Default | HTTP/1.1 Equivalent |
|---|---|---|---|
| CACHED_HTTP2_ASYNC_CLIENT | Custom HTTP/2 async client with SSL config | None | CACHED_HTTP_CLIENT |
| enableALPN | Negotiate h2 with TLS ALPN (HTTPS is always enforced) | true | N/A |
| supportedProtocols | Enabled TLS versions | TLSv1.2,TLSv1.3 | Similar |
| supportedCipherSuites | Enabled cipher suites | TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256 | Similar |
Advanced SSL Configuration for HTTP/2
For enterprise deployments requiring specific SSL configurations:
<transportSender name="h2" class="org.apache.axis2.transport.h2.impl.httpclient5.H2TransportSender"> <parameter name="PROTOCOL">HTTP/2.0</parameter> <!-- SSL/TLS Configuration (HTTPS is always enforced) --> <parameter name="supportedProtocols">TLSv1.2,TLSv1.3</parameter> <parameter name="supportedCipherSuites">TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256</parameter> <parameter name="enableALPN">true</parameter> </transportSender>
Hostname verification and certificate validation have no axis2.xml parameters. To change them (for example to trust a self-signed certificate, as in the example above), supply your own client through CACHED_HTTP2_ASYNC_CLIENT.
Client Certificate Authentication
For mutual TLS (client certificate authentication) with HTTP/2:
// Load client certificate and private key
KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
clientKeyStore.load(new FileInputStream("client-cert.p12"), "password".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "password".toCharArray());
// SSL Context with client certificate
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, new SecureRandom());
// Configure HTTP/2 client with client certificate authentication
TlsStrategy tlsStrategy = ClientTlsStrategyBuilder.create()
.setSslContext(sslContext)
.setTlsDetailsFactory(sslEngine -> {
SSLParameters sslParams = sslEngine.getSSLParameters();
sslParams.setApplicationProtocols(new String[]{"h2", "http/1.1"});
sslParams.setNeedClientAuth(true); // Require client authentication
sslEngine.setSSLParameters(sslParams);
return null;
})
.build();
HTTP/2 vs HTTP/1.1 SSL Differences
Key differences in SSL handling between HTTP/1.1 and HTTP/2:
- ALPN Support: HTTP/2 requires ALPN negotiation for protocol selection
- TLS Version: HTTP/2 requires TLS 1.2 or higher (TLS 1.3 recommended)
- Cipher Suites: HTTP/2 has specific cipher suite requirements (RFC 7540)
- Async Architecture: Uses CloseableHttpAsyncClient instead of CloseableHttpClient
- Connection Multiplexing: Single SSL connection handles multiple streams
- Fallback Handling: Automatic fallback to HTTP/1.1 if HTTP/2 negotiation fails
SSL Notes
HTTP/2 requires TLS 1.2+ with ALPN. Use OpenJDK 17+ (ALPN built in; Java 17 is the Axis2 minimum). If ALPN negotiation fails, the transport falls back to HTTP/1.1 automatically (no configuration flag required).
Apache Axis2
