17. HTTP Support

17.1 Introduction

The HTTP support allows for the execution of HTTP requests and the processing of inbound HTTP requests. Because interaction over HTTP is always synchronous, even if all that is returned is a 200 status code, the HTTP support consists of two gateway implementations: HttpInboundEndpoint and HttpRequestExecutingMessageHandler.

17.2 Http Inbound Gateway

To receive messages over HTTP, you need to use an HTTP Inbound Channel Adapter or Gateway. To support the HTTP Inbound Adapters, they need to be deployed within a servlet container such as Apache Tomcat or Jetty. The easiest way to do this is to use Spring’s HttpRequestHandlerServlet, by providing the following servlet definition in the web.xml file:

<servlet>
    <servlet-name>inboundGateway</servlet-name>
    <servlet-class>o.s.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>

Notice that the servlet name matches the bean name. For more information on using the HttpRequestHandlerServlet, see chapter "http://static.springsource.org/spring/docs/current/spring-framework-reference/html/remoting.html[Remoting and web services using Spring]", which is part of the Spring Framework Reference documentation.

If you are running within a Spring MVC application, then the aforementioned explicit servlet definition is not necessary. In that case, the bean name for your gateway can be matched against the URL path just like a Spring MVC Controller bean. For more information, please see the chapter "http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html[Web MVC framework]", which is part of the Spring Framework Reference documentation.

[Tip]Tip

For a sample application and the corresponding configuration, please see the Spring Integration Samples repository. It contains the Http Sample application demonstrating Spring Integration’s HTTP support.

Below is an example bean definition for a simple HTTP inbound endpoint.

<bean id="httpInbound"
  class="org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway">
  <property name="requestChannel" ref="httpRequestChannel" />
  <property name="replyChannel" ref="httpReplyChannel" />
</bean>

The HttpRequestHandlingMessagingGateway accepts a list of HttpMessageConverter instances or else relies on a default list. The converters allow customization of the mapping from HttpServletRequest to Message. The default converters encapsulate simple strategies, which for example will create a String message for a POST request where the content type starts with "text", see the Javadoc for full details. An additional flag (mergeWithDefaultConverters) can be set along with the list of custom HttpMessageConverter to add the default converters after the custom converters. By default this flag is set to false, meaning that the custom converters replace the default list.

Starting with Spring Integration 2.0, MultiPart File support is implemented. If the request has been wrapped as a MultipartHttpServletRequest, when using the default converters, that request will be converted to a Message payload that is a MultiValueMap containing values that may be byte arrays, Strings, or instances of Spring’s MultipartFile depending on the content type of the individual parts.

[Note]Note

The HTTP inbound Endpoint will locate a MultipartResolver in the context if one exists with the bean name "multipartResolver" (the same name expected by Spring’s DispatcherServlet). If it does in fact locate that bean, then the support for MultipartFiles will be enabled on the inbound request mapper. Otherwise, it will fail when trying to map a multipart-file request to a Spring Integration Message. For more on Spring’s support for MultipartResolvers, refer to the Spring Reference Manual.

[Note]Note

If you wish to proxy a multipart/form-data to another server, it may be better to keep it in raw form. To handle this situation, do not add the multipartResolver bean to the context; configure the endpoint to expect a byte[] request; customize the message converters to include a ByteArrayHttpMessageConverter, and disable the default multipart converter. You may need some other converter(s) for the replies:

<int-http:inbound-gateway
                  channel="receiveChannel"
                  path="/inboundAdapter.htm"
                  request-payload-type="byte[]"
                  message-converters="converters"
                  merge-with-default-converters="false"
                  supported-methods="POST" />

<util:list id="converters">
    <beans:bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
    <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter" />
    <beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</util:list>

In sending a response to the client there are a number of ways to customize the behavior of the gateway. By default the gateway will simply acknowledge that the request was received by sending a 200 status code back. It is possible to customize this response by providing a viewName to be resolved by the Spring MVC ViewResolver. In the case that the gateway should expect a reply to the Message then setting the expectReply flag (constructor argument) will cause the gateway to wait for a reply Message before creating an HTTP response. Below is an example of a gateway configured to serve as a Spring MVC Controller with a view name. Because of the constructor arg value of TRUE, it wait for a reply. This also shows how to customize the HTTP methods accepted by the gateway, which are POST and GET by default.

<bean id="httpInbound"
  class="org.springframework.integration.http.inbound.HttpRequestHandlingController">
  <constructor-arg value="true" /> <!-- indicates that a reply is expected -->
  <property name="requestChannel" ref="httpRequestChannel" />
  <property name="replyChannel" ref="httpReplyChannel" />
  <property name="viewName" value="jsonView" />
  <property name="supportedMethodNames" >
    <list>
      <value>GET</value>
      <value>DELETE</value>
    </list>
  </property>
</bean>

The reply message will be available in the Model map. The key that is used for that map entry by default is reply, but this can be overridden by setting the replyKey property on the endpoint’s configuration.

17.3 Http Outbound Gateway

To configure the HttpRequestExecutingMessageHandler write a bean definition like this:

<bean id="httpOutbound"
  class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">
  <constructor-arg value="http://localhost:8080/example" />
  <property name="outputChannel" ref="responseChannel" />
</bean>

This bean definition will execute HTTP requests by delegating to a RestTemplate. That template in turn delegates to a list of HttpMessageConverters to generate the HTTP request body from the Message payload. You can configure those converters as well as the ClientHttpRequestFactory instance to use:

<bean id="httpOutbound"
  class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">
  <constructor-arg value="http://localhost:8080/example" />
  <property name="outputChannel" ref="responseChannel" />
  <property name="messageConverters" ref="messageConverterList" />
  <property name="requestFactory" ref="customRequestFactory" />
</bean>

By default the HTTP request will be generated using an instance of SimpleClientHttpRequestFactory which uses the JDK HttpURLConnection. Use of the Apache Commons HTTP Client is also supported through the provided CommonsClientHttpRequestFactory which can be injected as shown above.

[Note]Note

In the case of the Outbound Gateway, the reply message produced by the gateway will contain all Message Headers present in the request message.

Cookies

Basic cookie support is provided by the transfer-cookies attribute on the outbound gateway. When set to true (default is false), a Set-Cookie header received from the server in a response will be converted to Cookie in the reply message. This header will then be used on subsequent sends. This enables simple stateful interactions, such as…​

...->logonGateway->...->doWorkGateway->...->logoffGateway->...

If transfer-cookies is false, any Set-Cookie header received will remain as Set-Cookie in the reply message, and will be dropped on subsequent sends.

[Note]Note: Empty Repsonse Bodies

HTTP is a request/response protocol. However the response may not have a body, just headers. In this case, the HttpRequestExecutingMessageHandler produces a reply Message with the payload being an org.springframework.http.ResponseEntity, regardless of any provided expected-response-type. According to the HTTP RFC Status Code Definitions, there are many statuses which identify that a response MUST NOT contain a message-body (e.g. 204 No Content). There are also cases where calls to the same URL might, or might not, return a response body; for example, the first request to an HTTP resource returns content, but the second does not (e.g. 304 Not Modified). In all cases, however, the http_statusCode message header is populated. This can be used in some routing logic after the Http Outbound Gateway. You could also use a`<payload-type-router/>` to route messages with an ResponseEntity to a different flow than that used for responses with a body.

[Note]Note: expected-response-type

Further to the note above regarding empty response bodies, if a response does contain a body, you must provide an appropriate expected-response-type attribute or, again, you will simply receive a ResponseEntity with no body. The expected-response-type must be compatible with the (configured or default) HttpMessageConverter s and the Content-Type header in the response. Of course, this can be an abstract class, or even an interface (such as java.io.Serializable when using java serialization and Content-Type: application/x-java-serialized-object).

17.4 HTTP Namespace Support

17.4.1 Introduction

Spring Integration provides an http namespace and the corresponding schema definition. To include it in your configuration, simply provide the following namespace declaration in your application context configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:int="http://www.springframework.org/schema/integration"
  xmlns:int-http="http://www.springframework.org/schema/integration/http"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/integration
    http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/http
    http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
    ...
</beans>

17.4.2 Inbound

The XML Namespace provides two components for handling HTTP Inbound requests. In order to process requests without returning a dedicated response, use the inbound-channel-adapter:

<int-http:inbound-channel-adapter id="httpChannelAdapter" channel="requests"
    supported-methods="PUT, DELETE"/>

To process requests that do expect a response, use an inbound-gateway:

<int-http:inbound-gateway id="inboundGateway"
    request-channel="requests"
    reply-channel="responses"/>

17.4.3 Request Mapping Support

[Note]Note

Spring Integration 3.0 is improving the REST support by introducing the IntegrationRequestMappingHandlerMapping. The implementation relies on the enhanced REST support provided by Spring Framework 3.1 or higher.

The parsing of the HTTP Inbound Gateway or the HTTP Inbound Channel Adapter registers an integrationRequestMappingHandlerMapping bean of type IntegrationRequestMappingHandlerMapping, in case there is none registered, yet. This particular implementation of the HandlerMapping delegates its logic to the RequestMappingInfoHandlerMapping. The implementation provides similar functionality as the one provided by the org.springframework.web.bind.annotation.RequestMapping annotation in Spring MVC.

[Note]Note

For more information, please see Mapping Requests With @RequestMapping.

For this purpose, Spring Integration 3.0 introduces the <request-mapping> sub-element. This optional sub-element can be added to the <http:inbound-channel-adapter> and the <http:inbound-gateway>. It works in conjunction with the path and supported-methods attributes:

<inbound-gateway id="inboundController"
    request-channel="requests"
    reply-channel="responses"
    path="/foo/{fooId}"
    supported-methods="GET"
    view-name="foo"
    error-code="oops">
   <request-mapping headers="User-Agent"
     params="myParam=myValue"
     consumes="application/json"
     produces="!text/plain"/>
</inbound-gateway>

Based on this configuration, the namespace parser creates an instance of the IntegrationRequestMappingHandlerMapping (if none exists, yet), a HttpRequestHandlingController bean and associated with it an instance of RequestMapping, which in turn, is converted to the Spring MVC RequestMappingInfo.

The <request-mapping> sub-element provides the following attributes:

  • headers
  • params
  • consumes
  • produces

With the path and supported-methods attributes of the <http:inbound-channel-adapter> or the <http:inbound-gateway>, <request-mapping> attributes translate directly into the respective options provided by the org.springframework.web.bind.annotation.RequestMapping annotation in Spring MVC.

The <request-mapping> sub-element allows you to configure several Spring Integration HTTP Inbound Endpoints to the same path (or even the same supported-methods) and to provide different downstream message flows based on incoming HTTP requests.

Alternatively, you can also declare just one HTTP Inbound Endpoint and apply routing and filtering logic within the Spring Integration flow to achieve the same result. This allows you to get the Message into the flow as early as possibly, e.g.:

<int-http:inbound-gateway request-channel="httpMethodRouter"
    supported-methods="GET,DELETE"
    path="/process/{entId}"
    payload-expression="#pathVariables.entId"/>

<int:router input-channel="httpMethodRouter" expression="headers.http_requestMethod">
    <int:mapping value="GET" channel="in1"/>
    <int:mapping value="DELETE" channel="in2"/>
</int:router>

<int:service-activator input-channel="in1" ref="service" method="getEntity"/>

<int:service-activator input-channel="in2" ref="service" method="delete"/>

For more information regarding Handler Mappings, please see: Handler Mappings.

17.4.4 Cross-Origin Resource Sharing (CORS) Support

Starting with version 4.2 the <http:inbound-channel-adapter> and <http:inbound-gateway> can be configured with a <cross-origin> sub-element. It represents the same options as Spring MVC’s @CrossOrigin for @Controller methods and allows the configuration of Cross-origin resource sharing (CORS) for Spring Integration HTTP endpoints:

  • origin - List of allowed origins. * means that all origins are allowed. These values are placed in the Access-Control-Allow-Origin header of both the pre-flight and actual responses. Default value is *.
  • allowed-headers - Indicates which request headers can be used during the actual request. * means that all headers asked by the client are allowed. This property controls the value of the pre-flight response’s Access-Control-Allow-Headers header. Default value is *.
  • exposed-headers - List of response headers that the user-agent will allow the client to access. This property controls the value of the actual response’s Access-Control-Expose-Headers header.
  • method - The HTTP request methods to allow: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. Methods specified here overrides those in supported-methods.
  • allow-credentials - Set to true if the the browser should include any cookies associated to the domain of the request, or false if it should not. Empty string "" means undefined. If true, the pre-flight response will include the header Access-Control-Allow-Credentials=true. Default value is true.
  • max-age - Controls the cache duration for pre-flight responses. Setting this to a reasonable value can reduce the number of pre-flight request/response interactions required by the browser. This property controls the value of the Access-Control-Max-Age header in the pre-flight response. A value of -1 means undefined. Default value is 1800 seconds, or 30 minutes.

The CORS Java Configuration is represented by the org.springframework.integration.http.inbound.CrossOrigin class, instances of which can be injected to the HttpRequestHandlingEndpointSupport beans.

17.4.5 Response StatusCode

Starting with version 4.1 the <http:inbound-channel-adapter> can be configured with a status-code-expression to override the default 200 OK status. The expression must return an object which can be converted to an org.springframework.http.HttpStatus enum value. The evaluationContext has a BeanResolver but no variables, so the usage of this attribute is somewhat limited. An example might be to resolve, at runtime, some scoped Bean that returns a status code value but, most likely, it will be set to a fixed value such as status-code=expression="204" (No Content), or status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT". By default, status-code-expression is null meaning that the normal 200 OK response status will be returned.

<http:inbound-channel-adapter id="inboundController"
       channel="requests" view-name="foo" error-code="oops"
       status-code-expression="T(org.springframework.http.HttpStatus).ACCEPTED">
   <request-mapping headers="BAR"/>
</http:inbound-channel-adapter>

The <http:inbound-gateway> resolves the status code from the http_statusCode header of the reply Message. Starting with version 4.2, the default response status code when no reply is received within the reply-timeout is 500 Internal Server Error. There are two ways to modify this behavior:

  • add a reply-timeout-status-code-expression - this has the same semantics as the status-code-expression on the inbound adapter.
  • Add an error-channel and return an appropriate message with an http status code header, such as…​
<int:chain input-channel="errors">
    <int:header-enricher>
        <int:header name="http_statusCode" value="504" />
    </int:header-enricher>
    <int:transformer expression="payload.message" />
</int:chain>

The payload of the ErrorMessage is a MessageTimeoutException; it must be transformed to something that can be converted by the gateway, such as a String; a good candidate is the exception’s message property, which is the value used when using the expression technique.

If the error flow times out after a main flow timeout, 500 Internal Server Error is returned, or the reply-timeout-status-code-expression is evaluated, if present.

[Note]Note

previously, the default status code for a timeout was 200 OK; to restore that behavior, set reply-timeout-status-code-expression="200".

17.4.6 URI Template Variables and Expressions

By Using the path attribute in conjunction with the payload-expression attribute as well as the header sub-element, you have a high degree of flexibility for mapping inbound request data.

In the following example configuration, an Inbound Channel Adapter is configured to accept requests using the following URI: /first-name/{firstName}/last-name/{lastName}

Using the payload-expression attribute, the URI template variable {firstName} is mapped to be the Message payload, while the {lastName} URI template variable will map to the lname Message header.

<int-http:inbound-channel-adapter id="inboundAdapterWithExpressions"
    path="/first-name/{firstName}/last-name/{lastName}"
    channel="requests"
    payload-expression="#pathVariables.firstName">
    <int-http:header name="lname" expression="#pathVariables.lastName"/>
</int-http:inbound-channel-adapter>

For more information about URI template variables, please see the Spring Reference Manual: uri template patterns.

Since Spring Integration 3.0, in addition to the existing #pathVariables and #requestParams variables being available in payload and header expressions, other useful variables have been added.

The entire list of available expression variables:

  • #requestParams - the MultiValueMap from the ServletRequest parameterMap.
  • #pathVariables - the Map from URI Template placeholders and their values;
  • #matrixVariables - the Map of MultiValueMap according to Spring MVC Specification. Note, #matrixVariables require Spring MVC 3.2 or higher;
  • #requestAttributes - the org.springframework.web.context.request.RequestAttributes associated with the current Request;
  • #requestHeaders - the org.springframework.http.HttpHeaders object from the current Request;
  • #cookies - the Map<String, Cookie> of javax.servlet.http.Cookie s from the current Request.

Note, all these values (and others) can be accessed within expressions in the downstream message flow via the ThreadLocal org.springframework.web.context.request.RequestAttributes variable, if that message flow is single-threaded and lives within the request thread:

<int-:transformer
	expression="T(org.springframework.web.context.request.RequestContextHolder).
	              requestAttributes.request.queryString"/>

17.4.7 Outbound

To configure the outbound gateway you can use the namespace support as well. The following code snippet shows the different configuration options for an outbound Http gateway. Most importantly, notice that the http-method and expected-response-type are provided. Those are two of the most commonly configured values. The default http-method is POST, and the default response type is null. With a null response type, the payload of the reply Message would contain the ResponseEntity as long as it’s http status is a success (non-successful status codes will throw Exceptions). If you are expecting a different type, such as a String, then provide that fully-qualified class name as shown below. See also the note about empty response bodies in Section 17.3, “Http Outbound Gateway”.

[Important]Important

Beginning with Spring Integration 2.1 the request-timeout attribute of the HTTP Outbound Gateway was renamed to reply-timeout to better reflect the intent.

<int-http:outbound-gateway id="example"
    request-channel="requests"
    url="http://localhost/test"
    http-method="POST"
    extract-request-payload="false"
    expected-response-type="java.lang.String"
    charset="UTF-8"
    request-factory="requestFactory"
    reply-timeout="1234"
    reply-channel="replies"/>
[Important]Important

Since Spring Integration 2.2, Java serialization over HTTP is no longer enabled by default. Previously, when setting the expected-response-type attribute to a Serializable object, the Accept header was not properly set up. Since Spring Integration 2.2, the SerializingHttpMessageConverter has now been updated to set the Accept header to application/x-java-serialized-object.

However, because this could cause incompatibility with existing applications, it was decided to no longer automatically add this converter to the HTTP endpoints. If you wish to use Java serialization, you will need to add the SerializingHttpMessageConverter to the appropriate endpoints, using the message-converters attribute, when using XML configuration, or using the setMessageConverters() method. Alternatively, you may wish to consider using JSON instead which is enabled by simply having Jackson on the classpath.

Beginning with Spring Integration 2.2 you can also determine the HTTP Method dynamically using SpEL and the http-method-expression attribute. Note that this attribute is obviously murually exclusive with http-method You can also use expected-response-type-expression attribute instead of expected-response-type and provide any valid SpEL expression that determines the type of the response.

<int-http:outbound-gateway id="example"
    request-channel="requests"
    url="http://localhost/test"
    http-method-expression="headers.httpMethod"
    extract-request-payload="false"
    expected-response-type-expression="payload"
    charset="UTF-8"
    request-factory="requestFactory"
    reply-timeout="1234"
    reply-channel="replies"/>

If your outbound adapter is to be used in a unidirectional way, then you can use an outbound-channel-adapter instead. This means that a successful response will simply execute without sending any Messages to a reply channel. In the case of any non-successful response status code, it will throw an exception. The configuration looks very similar to the gateway:

<int-http:outbound-channel-adapter id="example"
    url="http://localhost/example"
    http-method="GET"
    channel="requests"
    charset="UTF-8"
    extract-payload="false"
    expected-response-type="java.lang.String"
    request-factory="someRequestFactory"
    order="3"
    auto-startup="false"/>
[Note]Note

To specify the URL; you can use either the url attribute or the url-expression attribute. The url is a simple string (with placedholders for URI variables, as described below); the url-expression is a SpEL expression, with the Message as the root object, enabling dynamic urls. The url resulting from the expression evaluation can still have placeholders for URI variables.

In previous releases, some users used the place holders to replace the entire URL with a URI variable. Changes in Spring 3.1 can cause some issues with escaped characters, such as ?. For this reason, it is recommended that if you wish to generate the URL entirely at runtime, you use the url-expression attribute.

17.4.8 Mapping URI Variables

If your URL contains URI variables, you can map them using the uri-variable sub-element. This sub-element is available for the Http Outbound Gateway and the Http Outbound Channel Adapter.

<int-http:outbound-gateway id="trafficGateway"
    url="http://local.yahooapis.com/trafficData?appid=YdnDemo&amp;zip={zipCode}"
    request-channel="trafficChannel"
    http-method="GET"
    expected-response-type="java.lang.String">
    <int-http:uri-variable name="zipCode" expression="payload.getZip()"/>
</int-http:outbound-gateway>

The uri-variable sub-element defines two attributes: name and expression. The name attribute identifies the name of the URI variable, while the expression attribute is used to set the actual value. Using the expression attribute, you can leverage the full power of the Spring Expression Language (SpEL) which gives you full dynamic access to the message payload and the message headers. For example, in the above configuration the getZip() method will be invoked on the payload object of the Message and the result of that method will be used as the value for the URI variable named zipCode.

Since Spring Integration 3.0, HTTP Outbound Endpoints support the uri-variables-expression attribute to specify an Expression which should be evaluated, resulting in a Map for all URI variable placeholders within the URL template. It provides a mechanism whereby different variable expressions can be used, based on the outbound message. This attribute is mutually exclusive with the <uri-variable/> sub-element:

<int-http:outbound-gateway
     url="http://foo.host/{foo}/bars/{bar}"
     request-channel="trafficChannel"
     http-method="GET"
     uri-variables-expression="@uriVariablesBean.populate(payload)"
     expected-response-type="java.lang.String"/>

where uriVariablesBean might be:

public class UriVariablesBean {
	private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();

	public Map<String, ?> populate(Object payload) {
		Map<String, Object> variables = new HashMap<String, Object>();
		if (payload instanceOf String.class)) {
			variables.put("foo", "foo"));
		}
		else {
			variables.put("foo", EXPRESSION_PARSER.parseExpression("headers.bar"));
		}
		return variables;
	}

}
[Note]Note

The uri-variables-expression must evaluate to a Map. The values of the Map must be instances of String or Expression. This Map is provided to an ExpressionEvalMap for further resolution of URI variable placeholders using those expressions in the context of the outbound Message.

17.4.9 Controlling URI Encoding

By default, the URL string is encoded (see UriComponentsBuilder) to the URI object before sending the request. In some scenarios with a non-standard URI (e.g. the RabbitMQ Rest API) it is undesirable to perform the encoding. The <http:outbound-gateway/> and <http:outbound-channel-adapter/> provide an encode-uri attribute. To disable encoding the URL, this attribute should be set to false (by default it is true). If you wish to partially encode some of the URL, this can be achieved using an expression within a <uri-variable/>:

<http:outbound-gateway url="http://somehost/%2f/fooApps?bar={param}" encode-uri="false">
          <http:uri-variable name="param"
            expression="T(org.apache.commons.httpclient.util.URIUtil)
                                             .encodeWithinQuery('Hello World!')"/>
</http:outbound-gateway>

17.5 Timeout Handling

In the context of HTTP components, there are two timing areas that have to be considered.

Timeouts when interacting with Spring Integration Channels

Timeouts when interacting with a remote HTTP server

First, the components interact with Message Channels, for which timeouts can be specified. For example, an HTTP Inbound Gateway will forward messages received from connected HTTP Clients to a Message Channel (Request Timeout) and consequently the HTTP Inbound Gateway will receive a reply Message from the Reply Channel (Reply Timeout) that will be used to generate the HTTP Response. Please see the figure below for an illustration.

Figure 17.1. How timeout settings apply to an HTTP Inbound Gateway

http inbound gateway

For outbound endpoints, the second thing to consider is timing while interacting with the remote server.

Figure 17.2. How timeout settings apply to an HTTP Outbound Gateway

http outbound gateway

You may want to configure the HTTP related timeout behavior, when making active HTTP requests using the HTTP Oubound Gateway or the HTTP Outbound Channel Adapter. In those instances, these two components use Spring’shttp://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html[RestTemplate] support to execute HTTP requests.

In order to configure timeouts for the HTTP Oubound Gateway and the HTTP Outbound Channel Adapter, you can either reference a RestTemplate bean directly, using the rest-template attribute, or you can provide a reference to a ClientHttpRequestFactory bean using the request-factory attribute. Spring provides the following implementations of the ClientHttpRequestFactory interface:

SimpleClientHttpRequestFactory - Uses standard J2SE facilities for making HTTP Requests

HttpComponentsClientHttpRequestFactory - Uses Apache HttpComponents HttpClient (Since Spring 3.1)

ClientHttpRequestFactory - Uses Jakarta Commons HttpClient (Deprecated as of Spring 3.1)

If you don’t explicitly configure the request-factory or rest-template attribute respectively, then a default RestTemplate which uses a SimpleClientHttpRequestFactory will be instantiated.

[Note]Note

With some JVM implementations, the handling of timeouts using the URLConnection class may not be consistent.

E.g. from the Java™ Platform, Standard Edition 6 API Specification on setConnectTimeout: [quote] Some non-standard implmentation of this method may ignore the specified timeout. To see the connect timeout set, please call getConnectTimeout().

Please test your timeouts if you have specific needs. Consider using the HttpComponentsClientHttpRequestFactory which, in turn, uses Apache HttpComponents HttpClient instead.

[Important]Important

When using the Apache HttpComponents HttpClient with a Pooling Connection Manager, be aware that, by default, the connection manager will create no more than 2 concurrent connections per given route and no more than 20 connections in total. For many real-world applications these limits may prove too constraining. Refer to the Apache documentation (link above) for information about configuring this important component.

Here is an example of how to configure an HTTP Outbound Gateway using a SimpleClientHttpRequestFactory, configured with connect and read timeouts of 5 seconds respectively:

<int-http:outbound-gateway url="http://www.google.com/ig/api?weather={city}"
                           http-method="GET"
                           expected-response-type="java.lang.String"
                           request-factory="requestFactory"
                           request-channel="requestChannel"
                           reply-channel="replyChannel">
    <int-http:uri-variable name="city" expression="payload"/>
</int-http:outbound-gateway>

<bean id="requestFactory"
      class="org.springframework.http.client.SimpleClientHttpRequestFactory">
    <property name="connectTimeout" value="5000"/>
    <property name="readTimeout"    value="5000"/>
</bean>

HTTP Outbound Gateway

For the HTTP Outbound Gateway, the XML Schema defines only the reply-timeout. The reply-timeout maps to the sendTimeout property of the org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler class. More precisely, the property is set on the extended AbstractReplyProducingMessageHandler class, which ultimatelly sets the property on the MessagingTemplate.

The value of the sendTimeout property defaults to "-1" and will be applied to the connected MessageChannel. This means, that depending on the implementation, the Message Channel’s_send_ method may block indefinitely. Furthermore, the sendTimeout property is only used, when the actual MessageChannel implementation has a blocking send (such as full bounded QueueChannel).

HTTP Inbound Gateway

For the HTTP Inbound Gateway, the XML Schema defines the request-timeout attribute, which will be used to set the requestTimeout property on the HttpRequestHandlingMessagingGateway class (on the extended MessagingGatewaySupport class). Secondly, the_reply-timeout_ attribute exists and it maps to the replyTimeout property on the same class.

The default for both timeout properties is "1000ms". Ultimately, the request-timeout property will be used to set the sendTimeout on the used MessagingTemplate instance. The replyTimeout property on the other hand, will be used to set the receiveTimeout property on the used MessagingTemplate instance.

[Tip]Tip

In order to simulate connection timeouts, connect to a non-routable IP address, for example 10.255.255.10.

17.6 HTTP Proxy configuration

If you are behind a proxy and need to configure proxy settings for HTTP outbound adapters and/or gateways, you can apply one of two approaches. In most cases, you can rely on the standard Java System Properties that control the proxy settings. Otherwise, you can explicitly configure a Spring bean for the HTTP client request factory instance.

Standard Java Proxy configuration

There are 3 System Properties you can set to configure the proxy settings that will be used by the HTTP protocol handler:

  • http.proxyHost - the host name of the proxy server.
  • http.proxyPort - the port number, the default value being 80.
  • http.nonProxyHosts - a list of hosts that should be reached directly, bypassing the proxy. This is a list of patterns separated by |. The patterns may start or end with a * for wildcards. Any host matching one of these patterns will be reached through a direct connection instead of through a proxy.

And for HTTPS:

  • https.proxyHost - the host name of the proxy server.
  • https.proxyPort - the port number, the default value being 80.

For more information please refer to this document: http://download.oracle.com/javase/6/docs/technotes/guides/net/proxies.html

Spring’s SimpleClientHttpRequestFactory

If for any reason, you need more explicit control over the proxy configuration, you can use Spring’s SimpleClientHttpRequestFactory and configure its proxy property as such:

<bean id="requestFactory"
    class="org.springframework.http.client.SimpleClientHttpRequestFactory">
    <property name="proxy">
        <bean id="proxy" class="java.net.Proxy">
            <constructor-arg>
                <util:constant static-field="java.net.Proxy.Type.HTTP"/>
            </constructor-arg>
            <constructor-arg>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg value="123.0.0.1"/>
                    <constructor-arg value="8080"/>
                </bean>
            </constructor-arg>
        </bean>
    </property>
</bean>

17.7 HTTP Header Mappings

Spring Integration provides support for Http Header mapping for both HTTP Request and HTTP Responses.

By default all standard Http Headers as defined here http://en.wikipedia.org/wiki/List_of_HTTP_header_fields will be mapped from the message to HTTP request/response headers without further configuration. However if you do need further customization you may provide additional configuration via convenient namespace support. You can provide a comma-separated list of header names, and you can also include simple patterns with the * character acting as a wildcard. If you do provide such values, it will override the default behavior. Basically, it assumes you are in complete control at that point. However, if you do want to include all of the standard HTTP headers, you can use the shortcut patterns: HTTP_REQUEST_HEADERS and HTTP_RESPONSE_HEADERS. Here are some examples:

<int-http:outbound-gateway id="httpGateway"
    url="http://localhost/test2"
    mapped-request-headers="foo, bar"
    mapped-response-headers="X-*, HTTP_RESPONSE_HEADERS"
    channel="someChannel"/>

<int-http:outbound-channel-adapter id="httpAdapter"
    url="http://localhost/test2"
    mapped-request-headers="foo, bar, HTTP_REQUEST_HEADERS"
    channel="someChannel"/>

The adapters and gateways will use the DefaultHttpHeaderMapper which now provides two static factory methods for "inbound" and "outbound" adapters so that the proper direction can be applied (mapping HTTP requests/responses IN/OUT as appropriate).

If further customization is required you can also configure a DefaultHttpHeaderMapper independently and inject it into the adapter via the header-mapper attribute.

<int-http:outbound-gateway id="httpGateway"
    url="http://localhost/test2"
    header-mapper="headerMapper"
    channel="someChannel"/>

<bean id="headerMapper" class="o.s.i.http.support.DefaultHttpHeaderMapper">
    <property name="inboundHeaderNames" value="foo*, *bar, baz"/>
    <property name="outboundHeaderNames" value="a*b, d"/>
</bean>

Of course, you can even implement the HeaderMapper strategy interface directly and provide a reference to that if you need to do something other than what the DefaultHttpHeaderMapper supports.

17.8 HTTP Samples

17.8.1 Multipart HTTP request - RestTemplate (client) and Http Inbound Gateway (server)

This example demonstrates how simple it is to send a Multipart HTTP request via Spring’s RestTemplate and receive it with a Spring Integration HTTP Inbound Adapter. All we are doing is creating a MultiValueMap and populating it with multi-part data. The RestTemplate will take care of the rest (no pun intended) by converting it to a MultipartHttpServletRequest . This particular client will send a multipart HTTP Request which contains the name of the company as well as an image file with the company logo.

RestTemplate template = new RestTemplate();
String uri = "http://localhost:8080/multipart-http/inboundAdapter.htm";
Resource s2logo = 
   new ClassPathResource("org/springframework/samples/multipart/spring09_logo.png");
MultiValueMap map = new LinkedMultiValueMap();
map.add("company""SpringSource");
map.add("company-logo", s2logo);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("multipart""form-data"));
HttpEntity request = new HttpEntity(map, headers);
ResponseEntity<?> httpResponse = template.exchange(uri, HttpMethod.POST, request, null);

That is all for the client.

On the server side we have the following configuration:

<int-http:inbound-channel-adapter id="httpInboundAdapter"
    channel="receiveChannel"
    path="/inboundAdapter.htm"
    supported-methods="GET, POST"/>

<int:channel id="receiveChannel"/>

<int:service-activator input-channel="receiveChannel">
    <bean class="org.springframework.integration.samples.multipart.MultipartReceiver"/>
</int:service-activator>

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

The httpInboundAdapter will receive the request, convert it to a Message with a payload that is a LinkedMultiValueMap. We then are parsing that in the multipartReceiver service-activator;

public void receive(LinkedMultiValueMap<String, Object> multipartRequest){
    System.out.println("### Successfully received multipart request ###");
    for (String elementName : multipartRequest.keySet()) {
        if (elementName.equals("company")){
            System.out.println("\t" + elementName + " - " +
                ((String[]) multipartRequest.getFirst("company"))[0]);
        }
        else if (elementName.equals("company-logo")){
            System.out.println("\t" + elementName + " - as UploadedMultipartFile: " +
                ((UploadedMultipartFile) multipartRequest
                    .getFirst("company-logo")).getOriginalFilename());
        }
    }
}

You should see the following output:

### Successfully received multipart request ###
   company - SpringSource
   company-logo - as UploadedMultipartFile: spring09_logo.png