117.4952cce2.js 82.4 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[117],{542:function(e,t,a){"use strict";a.r(t);var n=a(56),o=Object(n.a)({},(function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[a("h1",{attrs:{id:"http-support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-support"}},[e._v("#")]),e._v(" HTTP Support")]),e._v(" "),a("h2",{attrs:{id:"http-support-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-support-2"}},[e._v("#")]),e._v(" HTTP Support")]),e._v(" "),a("p",[e._v("Spring Integration’s HTTP support allows for the running of HTTP requests and the processing of inbound HTTP requests.\nThe HTTP support consists of the following gateway implementations: "),a("code",[e._v("HttpInboundEndpoint")]),e._v(" and "),a("code",[e._v("HttpRequestExecutingMessageHandler")]),e._v(".\nSee also "),a("RouterLink",{attrs:{to:"/en/spring-integration/webflux.html#webflux"}},[e._v("WebFlux Support")]),e._v(".")],1),e._v(" "),a("p",[e._v("You need to include this dependency into your project:")]),e._v(" "),a("p",[e._v("Maven")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("<dependency>\n    <groupId>org.springframework.integration</groupId>\n    <artifactId>spring-integration-http</artifactId>\n    <version>5.5.9</version>\n</dependency>\n")])])]),a("p",[e._v("Gradle")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('compile "org.springframework.integration:spring-integration-http:5.5.9"\n')])])]),a("p",[e._v("The "),a("code",[e._v("javax.servlet:javax.servlet-api")]),e._v(" dependency must be provided on the target Servlet container.")]),e._v(" "),a("h3",{attrs:{id:"http-inbound-components"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-inbound-components"}},[e._v("#")]),e._v(" Http Inbound Components")]),e._v(" "),a("p",[e._v("To receive messages over HTTP, you need to use an HTTP inbound channel adapter or an HTTP inbound gateway.\nTo support the HTTP inbound adapters, they need to be deployed within a servlet container such as "),a("a",{attrs:{href:"https://tomcat.apache.org/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apache Tomcat"),a("OutboundLink")],1),e._v(" or "),a("a",{attrs:{href:"https://www.eclipse.org/jetty/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Jetty"),a("OutboundLink")],1),e._v(".\nThe easiest way to do this is to use Spring’s "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/context/support/HttpRequestHandlerServlet.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("HttpRequestHandlerServlet")]),a("OutboundLink")],1),e._v(", by providing the following servlet definition in the "),a("code",[e._v("web.xml")]),e._v(" file:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("<servlet>\n    <servlet-name>inboundGateway</servlet-name>\n    <servlet-class>o.s.web.context.support.HttpRequestHandlerServlet</servlet-class>\n</servlet>\n")])])]),a("p",[e._v("Notice that the servlet name matches the bean name.\nFor more information on using the "),a("code",[e._v("HttpRequestHandlerServlet")]),e._v(", see "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/html/remoting.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Remoting and web services using Spring"),a("OutboundLink")],1),e._v(", which is part of the Spring Framework Reference documentation.")]),e._v(" "),a("p",[e._v("If you are running within a Spring MVC application, then the aforementioned explicit servlet definition is not necessary.\nIn that case, the bean name for your gateway can be matched against the URL path as you would for a Spring MVC Controller bean.\nFor more information, see"),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc",target:"_blank",rel:"noopener noreferrer"}},[e._v("Web MVC framework"),a("OutboundLink")],1),e._v(", which is part of the Spring Framework Reference documentation.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("For a sample application and the corresponding configuration, see the "),a("a",{attrs:{href:"https://github.com/spring-projects/spring-integration-samples",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spring Integration Samples"),a("OutboundLink")],1),e._v(" repository."),a("br"),e._v("It contains the "),a("a",{attrs:{href:"https://github.com/spring-projects/spring-integration-samples/tree/main/basic/http",target:"_blank",rel:"noopener noreferrer"}},[e._v("HTTP sample"),a("OutboundLink")],1),e._v(" application, which demonstrates Spring Integration’s HTTP support.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("The following example bean defines an HTTP inbound endpoint:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<bean id="httpInbound"\n  class="org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway">\n  <property name="requestChannel" ref="httpRequestChannel" />\n  <property name="replyChannel" ref="httpReplyChannel" />\n</bean>\n')])])]),a("p",[e._v("The "),a("code",[e._v("HttpRequestHandlingMessagingGateway")]),e._v(" accepts a list of "),a("code",[e._v("HttpMessageConverter")]),e._v(" instances or else relies on a default list.\nThe converters allow customization of the mapping from "),a("code",[e._v("HttpServletRequest")]),e._v(" to "),a("code",[e._v("Message")]),e._v(".\nThe default converters encapsulate simple strategies, which (for example) create a "),a("code",[e._v("String")]),e._v(" message for a "),a("code",[e._v("POST")]),e._v(" request where the content type starts with "),a("code",[e._v("text")]),e._v(".\nSee the "),a("a",{attrs:{href:"https://docs.spring.io/spring-integration/api/index.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("Javadoc"),a("OutboundLink")],1),e._v(" for full details.\nAn additional flag ("),a("code",[e._v("mergeWithDefaultConverters")]),e._v(") can be set along with the list of custom "),a("code",[e._v("HttpMessageConverter")]),e._v(" to add the default converters after the custom converters.\nBy default, this flag is set to "),a("code",[e._v("false")]),e._v(", meaning that the custom converters replace the default list.")]),e._v(" "),a("p",[e._v("The message conversion process uses the (optional) "),a("code",[e._v("requestPayloadType")]),e._v(" property and the incoming "),a("code",[e._v("Content-Type")]),e._v(" header.\nStarting with version 4.3, if a request has no content type header, "),a("code",[e._v("application/octet-stream")]),e._v(" is assumed, as recommended by "),a("code",[e._v("RFC 2616")]),e._v(".\nPreviously, the body of such messages was ignored.")]),e._v(" "),a("p",[e._v("Spring Integration 2.0 implemented multipart file support.\nIf the request has been wrapped as a "),a("code",[e._v("MultipartHttpServletRequest")]),e._v(", when you use the default converters, that request is converted to a "),a("code",[e._v("Message")]),e._v(" payload that is a "),a("code",[e._v("MultiValueMap")]),e._v(" containing values that may be byte arrays, strings, or instances of Spring’s "),a("code",[e._v("MultipartFile")]),e._v(", depending on the content type of the individual parts.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("The HTTP inbound endpoint locates a "),a("code",[e._v("MultipartResolver")]),e._v(" in the context if one has a bean name of "),a("code",[e._v("multipartResolver")]),e._v(" (the same name expected by Spring’s "),a("code",[e._v("DispatcherServlet")]),e._v(")."),a("br"),e._v("If it does locate that bean, the support for multipart files is enabled on the inbound request mapper."),a("br"),e._v("Otherwise, it fails when it tries to map a multipart file request to a Spring Integration "),a("code",[e._v("Message")]),e._v("."),a("br"),e._v("For more on Spring’s support for "),a("code",[e._v("MultipartResolver")]),e._v(", see the "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-multipart",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spring Reference Manual"),a("OutboundLink")],1),e._v(".")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("If you wish to proxy a "),a("code",[e._v("multipart/form-data")]),e._v(" to another server, it may be better to keep it in raw form."),a("br"),e._v("To handle this situation, do not add the "),a("code",[e._v("multipartResolver")]),e._v(" bean to the context."),a("br"),e._v("Configure the endpoint to expect a "),a("code",[e._v("byte[]")]),e._v(" request, customize the message converters to include a "),a("code",[e._v("ByteArrayHttpMessageConverter")]),e._v(", and disable the default multipart converter."),a("br"),e._v("You may need some other converters for the replies."),a("br"),e._v("The following example shows such an arrangement:"),a("br"),a("br"),a("code",[e._v('<br/><int-http:inbound-gateway<br/> channel="receiveChannel"<br/> path="/inboundAdapter.htm"<br/> request-payload-type="byte[]"<br/> message-converters="converters"<br/> merge-with-default-converters="false"<br/> supported-methods="POST" /><br/><br/><util:list id="converters"><br/> <beans:bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /><br/> <beans:bean class="org.springframework.http.converter.StringHttpMessageConverter" /><br/> <beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /><br/></util:list><br/>')])])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("When you send a response to the client, you have a number of ways to customize the behavior of the gateway.\nBy default, the gateway acknowledges that the request was received by sending a "),a("code",[e._v("200")]),e._v(" status code back.\nIt is possible to customize this response by providing a 'viewName' to be resolved by the Spring MVC "),a("code",[e._v("ViewResolver")]),e._v(".\nIf the gateway should expect a reply to the "),a("code",[e._v("Message")]),e._v(", you can set the "),a("code",[e._v("expectReply")]),e._v(" flag (constructor argument) to cause the gateway to wait for a reply "),a("code",[e._v("Message")]),e._v(" before creating an HTTP response.\nThe following example configures a gateway to serve as a Spring MVC Controller with a view name:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<bean id="httpInbound"\n  class="org.springframework.integration.http.inbound.HttpRequestHandlingController">\n  <constructor-arg value="true" /> \x3c!-- indicates that a reply is expected --\x3e\n  <property name="requestChannel" ref="httpRequestChannel" />\n  <property name="replyChannel" ref="httpReplyChannel" />\n  <property name="viewName" value="jsonView" />\n  <property name="supportedMethodNames" >\n    <list>\n      <value>GET</value>\n      <value>DELETE</value>\n    </list>\n  </property>\n</bean>\n')])])]),a("p",[e._v("Because of the "),a("code",[e._v("constructor-arg")]),e._v(" value of "),a("code",[e._v("true")]),e._v(", it waits for a reply.\nThe preceding example also shows how to customize the HTTP methods accepted by the gateway, which are "),a("code",[e._v("POST")]),e._v(" and "),a("code",[e._v("GET")]),e._v(" by default.")]),e._v(" "),a("p",[e._v("The reply message is available in the model map.\nBy default, the key for that map entry is 'reply', but you can override this default by setting the 'replyKey' property on the endpoint’s configuration.")]),e._v(" "),a("h4",{attrs:{id:"payload-validation"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#payload-validation"}},[e._v("#")]),e._v(" Payload Validation")]),e._v(" "),a("p",[e._v("Starting with version 5.2, the HTTP inbound endpoints can be supplied with a "),a("code",[e._v("Validator")]),e._v(" to check a payload before sending into the channel.\nThis payload is already a result of conversion and extraction after "),a("code",[e._v("payloadExpression")]),e._v(" to narrow a validation scope in regards to the valuable data.\nThe validation failure handling is fully the same what we have in Spring MVC "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-exceptionhandlers",target:"_blank",rel:"noopener noreferrer"}},[e._v("Error Handling"),a("OutboundLink")],1),e._v(".")]),e._v(" "),a("h3",{attrs:{id:"http-outbound-components"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-outbound-components"}},[e._v("#")]),e._v(" HTTP Outbound Components")]),e._v(" "),a("p",[e._v("This section describes Spring Integration’s HTTP outbound components.")]),e._v(" "),a("h4",{attrs:{id:"using-httprequestexecutingmessagehandler"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-httprequestexecutingmessagehandler"}},[e._v("#")]),e._v(" Using "),a("code",[e._v("HttpRequestExecutingMessageHandler")])]),e._v(" "),a("p",[e._v("To configure the "),a("code",[e._v("HttpRequestExecutingMessageHandler")]),e._v(", write a bean definition similar to the following:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<bean id="httpOutbound"\n  class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">\n  <constructor-arg value="http://localhost:8080/example" />\n  <property name="outputChannel" ref="responseChannel" />\n</bean>\n')])])]),a("p",[e._v("This bean definition runs HTTP requests by delegating to a "),a("code",[e._v("RestTemplate")]),e._v(".\nThat template, in turn, delegates to a list of "),a("code",[e._v("HttpMessageConverter")]),e._v(" instances to generate the HTTP request body from the "),a("code",[e._v("Message")]),e._v(" payload.\nYou can configure those converters as well as the "),a("code",[e._v("ClientHttpRequestFactory")]),e._v(" instance to use, as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<bean id="httpOutbound"\n  class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler">\n  <constructor-arg value="http://localhost:8080/example" />\n  <property name="outputChannel" ref="responseChannel" />\n  <property name="messageConverters" ref="messageConverterList" />\n  <property name="requestFactory" ref="customRequestFactory" />\n</bean>\n')])])]),a("p",[e._v("By default, the HTTP request is generated by using an instance of "),a("code",[e._v("SimpleClientHttpRequestFactory")]),e._v(", which uses the JDK "),a("code",[e._v("HttpURLConnection")]),e._v(".\nUse of the Apache Commons HTTP Client is also supported through "),a("code",[e._v("CommonsClientHttpRequestFactory")]),e._v(", which you can inject (as shown earlier).")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("For the outbound gateway, the reply message produced by the gateway contains all the message headers that are present in the request message.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"using-cookies"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#using-cookies"}},[e._v("#")]),e._v(" Using Cookies")]),e._v(" "),a("p",[e._v("Basic cookie support is provided by the "),a("code",[e._v("transfer-cookies")]),e._v(" attribute on the outbound gateway.\nWhen set to "),a("code",[e._v("true")]),e._v(" (the default is "),a("code",[e._v("false")]),e._v("), a "),a("code",[e._v("Set-Cookie")]),e._v(" header received from the server in a response is converted to "),a("code",[e._v("Cookie")]),e._v(" in the reply message.\nThis header is then used on subsequent sends.\nThis enables simple stateful interactions, such as the following:")]),e._v(" "),a("p",[a("code",[e._v("…​→logonGateway→…​→doWorkGateway→…​→logoffGateway→…​")])]),e._v(" "),a("p",[e._v("If "),a("code",[e._v("transfer-cookies")]),e._v(" is "),a("code",[e._v("false")]),e._v(", any "),a("code",[e._v("Set-Cookie")]),e._v(" header received remains as "),a("code",[e._v("Set-Cookie")]),e._v(" in the reply message and is dropped on subsequent sends.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Empty Response Bodies"),a("br"),a("br"),e._v("HTTP is a request-response protocol."),a("br"),e._v("However, the response may not have a body, only headers."),a("br"),e._v("In this case, the "),a("code",[e._v("HttpRequestExecutingMessageHandler")]),e._v(" produces a reply "),a("code",[e._v("Message")]),e._v(" with the payload being an "),a("code",[e._v("org.springframework.http.ResponseEntity")]),e._v(", regardless of any provided "),a("code",[e._v("expected-response-type")]),e._v("."),a("br"),e._v("According to the "),a("a",{attrs:{href:"https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("HTTP RFC Status Code Definitions"),a("OutboundLink")],1),e._v(", there are many statuses that mandate that a response must not contain a message-body (for example, "),a("code",[e._v("204 No Content")]),e._v(")."),a("br"),e._v("There are also cases where calls to the same URL might or might not return a response body."),a("br"),e._v("For example, the first request to an HTTP resource returns content, but the second does not (returning a "),a("code",[e._v("304 Not Modified")]),e._v(")."),a("br"),e._v("In all cases, however, the "),a("code",[e._v("http_statusCode")]),e._v(" message header is populated."),a("br"),e._v("This can be used in some routing logic after the HTTP outbound gateway."),a("br"),e._v("You could also use a"),a("code",[e._v("\\<payload-type-router/\\>")]),e._v(" to route messages with a "),a("code",[e._v("ResponseEntity")]),e._v(" to a different flow than that used for responses with a body.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("expected-response-type"),a("br"),a("br"),e._v("Further to the preceding note about empty response bodies, if a response does contain a body, you must provide an appropriate "),a("code",[e._v("expected-response-type")]),e._v(" attribute or, again, you receive a "),a("code",[e._v("ResponseEntity")]),e._v(" with no body."),a("br"),e._v("The "),a("code",[e._v("expected-response-type")]),e._v(" must be compatible with the (configured or default) "),a("code",[e._v("HttpMessageConverter")]),e._v(" instances and the "),a("code",[e._v("Content-Type")]),e._v(" header in the response."),a("br"),e._v("This can be an abstract class or even an interface (such as "),a("code",[e._v("java.io.Serializable")]),e._v(" when you use Java serialization and "),a("code",[e._v("Content-Type: application/x-java-serialized-object")]),e._v(").")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("Starting with version 5.5, the "),a("code",[e._v("HttpRequestExecutingMessageHandler")]),e._v(" exposes an "),a("code",[e._v("extractResponseBody")]),e._v(" flag (which is "),a("code",[e._v("true")]),e._v(" by default) to return just the response body, or to return the whole "),a("code",[e._v("ResponseEntity")]),e._v(" as the reply message payload, independently of the provided "),a("code",[e._v("expectedResponseType")]),e._v(".\nIf a body is not present in the "),a("code",[e._v("ResponseEntity")]),e._v(", this flag is ignored and the whole "),a("code",[e._v("ResponseEntity")]),e._v(" is returned.")]),e._v(" "),a("h3",{attrs:{id:"http-namespace-support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-namespace-support"}},[e._v("#")]),e._v(" HTTP Namespace Support")]),e._v(" "),a("p",[e._v("Spring Integration provides an "),a("code",[e._v("http")]),e._v(" namespace and the corresponding schema definition.\nTo include it in your configuration, provide the following namespace declaration in your application context configuration file:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<?xml version="1.0" encoding="UTF-8"?>\n<beans xmlns="http://www.springframework.org/schema/beans"\n  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n  xmlns:int="http://www.springframework.org/schema/integration"\n  xmlns:int-http="http://www.springframework.org/schema/integration/http"\n  xsi:schemaLocation="\n    http://www.springframework.org/schema/beans\n    https://www.springframework.org/schema/beans/spring-beans.xsd\n    http://www.springframework.org/schema/integration\n    https://www.springframework.org/schema/integration/spring-integration.xsd\n    http://www.springframework.org/schema/integration/http\n    https://www.springframework.org/schema/integration/http/spring-integration-http.xsd">\n    ...\n</beans>\n')])])]),a("h4",{attrs:{id:"inbound"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#inbound"}},[e._v("#")]),e._v(" Inbound")]),e._v(" "),a("p",[e._v("The XML namespace provides two components for handling HTTP inbound requests: "),a("code",[e._v("inbound-channel-adapter")]),e._v(" and "),a("code",[e._v("inbound-gateway")]),e._v(".\nIn order to process requests without returning a dedicated response, use the "),a("code",[e._v("inbound-channel-adapter")]),e._v(".\nThe following example shows how to configure one:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:inbound-channel-adapter id="httpChannelAdapter" channel="requests"\n    supported-methods="PUT, DELETE"/>\n')])])]),a("p",[e._v("To process requests that do expect a response, use an "),a("code",[e._v("inbound-gateway")]),e._v(".\nThe following example shows how to configure one:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:inbound-gateway id="inboundGateway"\n    request-channel="requests"\n    reply-channel="responses"/>\n')])])]),a("h4",{attrs:{id:"request-mapping-support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#request-mapping-support"}},[e._v("#")]),e._v(" Request Mapping Support")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Spring Integration 3.0 improved the REST support by introducing the "),a("a",{attrs:{href:"https://docs.spring.io/spring-integration/api/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("IntegrationRequestMappingHandlerMapping")]),a("OutboundLink")],1),e._v("."),a("br"),e._v("The implementation relies on the enhanced REST support provided by Spring Framework 3.1 or higher.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("The parsing of the HTTP inbound gateway or the HTTP inbound channel adapter registers an "),a("code",[e._v("integrationRequestMappingHandlerMapping")]),e._v(" bean of type "),a("a",{attrs:{href:"https://docs.spring.io/spring-integration/api/org/springframework/integration/http/inbound/IntegrationRequestMappingHandlerMapping.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("IntegrationRequestMappingHandlerMapping")]),a("OutboundLink")],1),e._v(", in case one is not yet registered.\nThis particular implementation of the "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/HandlerMapping.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("HandlerMapping")]),a("OutboundLink")],1),e._v(" delegates its logic to "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/RequestMappingInfoHandlerMapping.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("RequestMappingInfoHandlerMapping")]),a("OutboundLink")],1),e._v(".\nThe implementation provides functionality similar to the "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("org.springframework.web.bind.annotation.RequestMapping")]),a("OutboundLink")],1),e._v(" annotation in Spring MVC.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("For more information, see "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestmapping",target:"_blank",rel:"noopener noreferrer"}},[e._v("Mapping Requests With "),a("code",[e._v("@RequestMapping")]),a("OutboundLink")],1),e._v(".")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("For this purpose, Spring Integration 3.0 introduces the "),a("code",[e._v("<request-mapping>")]),e._v(" element.\nYou can add this optional element to "),a("code",[e._v("<http:inbound-channel-adapter>")]),e._v(" and "),a("code",[e._v("<http:inbound-gateway>")]),e._v(".\nIt works in conjunction with the "),a("code",[e._v("path")]),e._v(" and "),a("code",[e._v("supported-methods")]),e._v(" attributes.\nThe following example shows how to configure it on an inbound gateway:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<inbound-gateway id="inboundController"\n    request-channel="requests"\n    reply-channel="responses"\n    path="/foo/{fooId}"\n    supported-methods="GET"\n    view-name="foo"\n    error-code="oops">\n   <request-mapping headers="User-Agent"\n     params="myParam=myValue"\n     consumes="application/json"\n     produces="!text/plain"/>\n</inbound-gateway>\n')])])]),a("p",[e._v("Based on the preceding configuration, the namespace parser creates an instance of the "),a("code",[e._v("IntegrationRequestMappingHandlerMapping")]),e._v(" (if none exists) and an "),a("code",[e._v("HttpRequestHandlingController")]),e._v(" bean and associates with it an instance of "),a("a",{attrs:{href:"https://docs.spring.io/spring-integration/api/org/springframework/integration/http/inbound/RequestMapping.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("RequestMapping")]),a("OutboundLink")],1),e._v(".\nThis "),a("code",[e._v("RequestMapping")]),e._v(" instance is, in turn, converted to the Spring MVC "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/RequestMappingInfo.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("RequestMappingInfo")]),a("OutboundLink")],1),e._v(".")]),e._v(" "),a("p",[e._v("The "),a("code",[e._v("<request-mapping>")]),e._v(" element provides the following attributes:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("headers")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("params")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("consumes")])])]),e._v(" "),a("li",[a("p",[a("code",[e._v("produces")])])])]),e._v(" "),a("p",[e._v("With the "),a("code",[e._v("path")]),e._v(" and "),a("code",[e._v("supported-methods")]),e._v(" attributes of the "),a("code",[e._v("<http:inbound-channel-adapter>")]),e._v(" or the "),a("code",[e._v("<http:inbound-gateway>")]),e._v(", "),a("code",[e._v("<request-mapping>")]),e._v(" attributes translate directly into the respective options provided by the "),a("code",[e._v("org.springframework.web.bind.annotation.RequestMapping")]),e._v(" annotation in Spring MVC.")]),e._v(" "),a("p",[e._v("The "),a("code",[e._v("<request-mapping>")]),e._v(" element lets you configure several Spring Integration HTTP inbound endpoints to the same "),a("code",[e._v("path")]),e._v(" (or even the same "),a("code",[e._v("supported-methods")]),e._v(") and lets you provide different downstream message flows based on incoming HTTP requests.")]),e._v(" "),a("p",[e._v("Alternatively, you can also declare only one HTTP inbound endpoint and apply routing and filtering logic within the Spring Integration flow to achieve the same result.\nThis lets you get the "),a("code",[e._v("Message")]),e._v(" into the flow as early as possibly.\nThe following example shows how to do so:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:inbound-gateway request-channel="httpMethodRouter"\n    supported-methods="GET,DELETE"\n    path="/process/{entId}"\n    payload-expression="#pathVariables.entId"/>\n\n<int:router input-channel="httpMethodRouter" expression="headers.http_requestMethod">\n    <int:mapping value="GET" channel="in1"/>\n    <int:mapping value="DELETE" channel="in2"/>\n</int:router>\n\n<int:service-activator input-channel="in1" ref="service" method="getEntity"/>\n\n<int:service-activator input-channel="in2" ref="service" method="delete"/>\n')])])]),a("p",[e._v("For more information regarding handler mappings, see "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("the Spring Framework Web Servlet documentation"),a("OutboundLink")],1),e._v(" or "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("the Spring Framework Web Reactive documentation"),a("OutboundLink")],1),e._v(".")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("The "),a("code",[e._v("IntegrationRequestMappingHandlerMapping")]),e._v(" extends the Spring MVC "),a("code",[e._v("RequestMappingHandlerMapping")]),e._v(" class, inheriting most of its logic, especially "),a("code",[e._v("handleNoMatch(Set, String, HttpServletRequest)")]),e._v(", which throws a specific "),a("code",[e._v("4xx")]),e._v(" error for the HTTP response, when mapping doesn’t match for some reason, preventing calls to any remaining mapping handlers in the application context."),a("br"),e._v("For this reason, configuring the same path for both Spring Integration and Spring MVC request mappings (e.g. "),a("code",[e._v("POST")]),e._v(" in one and "),a("code",[e._v("GET")]),e._v(" in the other) is not supported; the MVC mapping will not be found..")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"support"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#support"}},[e._v("#")]),e._v(" Support")]),e._v(" "),a("p",[e._v("Starting with version 4.2, you can configure the "),a("code",[e._v("<http:inbound-channel-adapter>")]),e._v(" and "),a("code",[e._v("<http:inbound-gateway>")]),e._v(" with a "),a("code",[e._v("<cross-origin>")]),e._v(" element.\nIt represents the same options as Spring MVC’s "),a("code",[e._v("@CrossOrigin")]),e._v(" for "),a("code",[e._v("@Controller")]),e._v(" annotations and allows the configuration of cross-origin resource sharing (CORS) for Spring Integration HTTP endpoints:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("origin")]),e._v(": List of allowed origins.\nThe "),a("code",[e._v("*")]),e._v(" means that all origins are allowed.\nThese values are placed in the "),a("code",[e._v("Access-Control-Allow-Origin")]),e._v(" header of both the pre-flight and actual responses.\nThe default value is "),a("code",[e._v("*")]),e._v(".")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("allowed-headers")]),e._v(": Indicates which request headers can be used during the actual request.\nThe "),a("code",[e._v("*")]),e._v(" means that all headers requested by the client are allowed.\nThis property controls the value of the pre-flight response’s "),a("code",[e._v("Access-Control-Allow-Headers")]),e._v(" header.\nThe default value is "),a("code",[e._v("*")]),e._v(".")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("exposed-headers")]),e._v(": List of response headers that the user-agent lets the client access.\nThis property controls the value of the actual response’s "),a("code",[e._v("Access-Control-Expose-Headers")]),e._v(" header.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("method")]),e._v(": The HTTP request methods to allow: "),a("code",[e._v("GET")]),e._v(", "),a("code",[e._v("POST")]),e._v(", "),a("code",[e._v("HEAD")]),e._v(", "),a("code",[e._v("OPTIONS")]),e._v(", "),a("code",[e._v("PUT")]),e._v(", "),a("code",[e._v("PATCH")]),e._v(", "),a("code",[e._v("DELETE")]),e._v(", "),a("code",[e._v("TRACE")]),e._v(".\nMethods specified here overrides those in "),a("code",[e._v("supported-methods")]),e._v(".")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("allow-credentials")]),e._v(": Set to "),a("code",[e._v("true")]),e._v(" if the browser should include any cookies associated to the domain of the request or "),a("code",[e._v("false")]),e._v(' if it should not.\nAn empty string ("") means undefined.\nIf '),a("code",[e._v("true")]),e._v(", the pre-flight response includes the "),a("code",[e._v("Access-Control-Allow-Credentials=true")]),e._v(" header.\nThe default value is "),a("code",[e._v("true")]),e._v(".")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("max-age")]),e._v(": Controls the cache duration for pre-flight responses.\nSetting this to a reasonable value can reduce the number of pre-flight request-response interactions required by the browser.\nThis property controls the value of the "),a("code",[e._v("Access-Control-Max-Age")]),e._v(" header in the pre-flight response.\nA value of "),a("code",[e._v("-1")]),e._v(" means undefined.\nThe default value is 1800 seconds (30 minutes).")])])]),e._v(" "),a("p",[e._v("The CORS Java Configuration is represented by the "),a("code",[e._v("org.springframework.integration.http.inbound.CrossOrigin")]),e._v(" class, instances of which can be injected into the "),a("code",[e._v("HttpRequestHandlingEndpointSupport")]),e._v(" beans.")]),e._v(" "),a("h4",{attrs:{id:"response-status-code"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#response-status-code"}},[e._v("#")]),e._v(" Response Status Code")]),e._v(" "),a("p",[e._v("Starting with version 4.1, you can configure the "),a("code",[e._v("<http:inbound-channel-adapter>")]),e._v(" with a "),a("code",[e._v("status-code-expression")]),e._v(" to override the default "),a("code",[e._v("200 OK")]),e._v(" status.\nThe expression must return an object that can be converted to an "),a("code",[e._v("org.springframework.http.HttpStatus")]),e._v(" enum value.\nThe "),a("code",[e._v("evaluationContext")]),e._v(" has a "),a("code",[e._v("BeanResolver")]),e._v(" and, starting with version 5.1, is supplied with the "),a("code",[e._v("RequestEntity<?>")]),e._v(" as root object.\nAn example might be to resolve, at runtime, some scoped bean that returns a status code value.\nHowever, most likely, it is set to a fixed value such as "),a("code",[e._v('status-code=expression="204"')]),e._v(" (No Content), or "),a("code",[e._v('status-code-expression="T(org.springframework.http.HttpStatus).NO_CONTENT"')]),e._v(".\nBy default, "),a("code",[e._v("status-code-expression")]),e._v(" is null, meaning that the normal '200 OK' response status is returned.\nUsing the "),a("code",[e._v("RequestEntity<?>")]),e._v(" as root object, the status code can be conditional e.g. on the request method, some header, URI content or even request body.\nThe following example shows how to set the status code to "),a("code",[e._v("ACCEPTED")]),e._v(":")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<http:inbound-channel-adapter id="inboundController"\n       channel="requests" view-name="foo" error-code="oops"\n       status-code-expression="T(org.springframework.http.HttpStatus).ACCEPTED">\n   <request-mapping headers="BAR"/>\n</http:inbound-channel-adapter>\n')])])]),a("p",[e._v("The "),a("code",[e._v("<http:inbound-gateway>")]),e._v(" resolves the 'status code' from the "),a("code",[e._v("http_statusCode")]),e._v(" header of the reply "),a("code",[e._v("Message")]),e._v(".\nStarting with version 4.2, the default response status code when no reply is received within the "),a("code",[e._v("reply-timeout")]),e._v(" is "),a("code",[e._v("500 Internal Server Error")]),e._v(".\nThere are two ways to modify this behavior:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("Add a "),a("code",[e._v("reply-timeout-status-code-expression")]),e._v(".\nThis has the same semantics as the "),a("code",[e._v("status-code-expression")]),e._v(" on the inbound adapter.")])]),e._v(" "),a("li",[a("p",[e._v("Add an "),a("code",[e._v("error-channel")]),e._v(" and return an appropriate message with an HTTP status code header, as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int:chain input-channel="errors">\n    <int:header-enricher>\n        <int:header name="http_statusCode" value="504" />\n    </int:header-enricher>\n    <int:transformer expression="payload.failedMessage" />\n</int:chain>\n')])])])])]),e._v(" "),a("p",[e._v("The payload of the "),a("code",[e._v("ErrorMessage")]),e._v(" is a "),a("code",[e._v("MessageTimeoutException")]),e._v(".\nIt must be transformed to something that can be converted by the gateway, such as a "),a("code",[e._v("String")]),e._v(".\nA good candidate is the exception’s message property, which is the value used when you use the "),a("code",[e._v("expression")]),e._v(" technique.")]),e._v(" "),a("p",[e._v("If the error flow times out after a main flow timeout, "),a("code",[e._v("500 Internal Server Error")]),e._v(" is returned, or, if the "),a("code",[e._v("reply-timeout-status-code-expression")]),e._v(" is present, it is evaluated.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Previously, the default status code for a timeout was "),a("code",[e._v("200 OK")]),e._v("."),a("br"),e._v("To restore that behavior, set "),a("code",[e._v('reply-timeout-status-code-expression="200"')]),e._v(".")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("Also starting with version 5.4, an error that is encountered while preparing the request message is sent to the error channel (if provided).\nA decision about throwing an appropriate exception should be done in the error flow by examining the exception.\nPreviously, any exceptions were simply thrown, causing an HTTP 500 server error response status, but in some cases the problem can be caused by incorrect request params, so a "),a("code",[e._v("ResponseStatusException")]),e._v(" with a 4xx client error status should be thrown instead.\nSee "),a("code",[e._v("ResponseStatusException")]),e._v(" for more information.\nThe "),a("code",[e._v("ErrorMessage")]),e._v(" sent to this error channel contains the original exception as the payload for analysis.\n==== URI Template Variables and Expressions")]),e._v(" "),a("p",[e._v("By using the "),a("code",[e._v("path")]),e._v(" attribute in conjunction with the "),a("code",[e._v("payload-expression")]),e._v(" attribute and the "),a("code",[e._v("header")]),e._v(" element, you have a high degree of flexibility for mapping inbound request data.")]),e._v(" "),a("p",[e._v("In the following example configuration, an inbound channel adapter is configured to accept requests using the following URI:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("/first-name/{firstName}/last-name/{lastName}\n")])])]),a("p",[e._v("When you use the "),a("code",[e._v("payload-expression")]),e._v(" attribute, the "),a("code",[e._v("{firstName}")]),e._v(" URI template variable maps to be the "),a("code",[e._v("Message")]),e._v(" payload, while the "),a("code",[e._v("{lastName}")]),e._v(" URI template variable maps to the "),a("code",[e._v("lname")]),e._v(" message header, as defined in the following example:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:inbound-channel-adapter id="inboundAdapterWithExpressions"\n    path="/first-name/{firstName}/last-name/{lastName}"\n    channel="requests"\n    payload-expression="#pathVariables.firstName">\n    <int-http:header name="lname" expression="#pathVariables.lastName"/>\n</int-http:inbound-channel-adapter>\n')])])]),a("p",[e._v("For more information about URI template variables, see "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-requestmapping-uri-templates",target:"_blank",rel:"noopener noreferrer"}},[e._v("uri template patterns"),a("OutboundLink")],1),e._v(" in the Spring Reference Manual.")]),e._v(" "),a("p",[e._v("Since Spring Integration 3.0, in addition to the existing "),a("code",[e._v("#pathVariables")]),e._v(" and "),a("code",[e._v("#requestParams")]),e._v(" variables being available in payload and header expressions, we added other useful expression variables:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("#requestParams")]),e._v(": The "),a("code",[e._v("MultiValueMap")]),e._v(" from the "),a("code",[e._v("ServletRequest")]),e._v(" "),a("code",[e._v("parameterMap")]),e._v(".")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("#pathVariables")]),e._v(": The "),a("code",[e._v("Map")]),e._v(" from URI Template placeholders and their values.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("#matrixVariables")]),e._v(": The "),a("code",[e._v("Map")]),e._v(" of "),a("code",[e._v("MultiValueMap")]),e._v(" according to the "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-matrix-variables",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spring MVC Specification"),a("OutboundLink")],1),e._v(".\nNote that "),a("code",[e._v("#matrixVariables")]),e._v(" requires Spring MVC 3.2 or higher.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("#requestAttributes")]),e._v(": The "),a("code",[e._v("org.springframework.web.context.request.RequestAttributes")]),e._v(" associated with the current request.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("#requestHeaders")]),e._v(": The "),a("code",[e._v("org.springframework.http.HttpHeaders")]),e._v(" object from the current request.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("#cookies")]),e._v(": The "),a("code",[e._v("Map<String, Cookie>")]),e._v(" of "),a("code",[e._v("javax.servlet.http.Cookie")]),e._v(" instances from the current request.")])])]),e._v(" "),a("p",[e._v("Note that all these values (and others) can be accessed within expressions in the downstream message flow through the "),a("code",[e._v("ThreadLocal")]),e._v(" "),a("code",[e._v("org.springframework.web.context.request.RequestAttributes")]),e._v(" variable, if that message flow is single-threaded and lives within the request thread.\nThe following example configures a transformer that uses an "),a("code",[e._v("expression")]),e._v(" attribute:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-:transformer\n    expression="T(org.springframework.web.context.request.RequestContextHolder).\n                  requestAttributes.request.queryString"/>\n')])])]),a("h4",{attrs:{id:"outbound"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#outbound"}},[e._v("#")]),e._v(" Outbound")]),e._v(" "),a("p",[e._v("To configure the outbound gateway, you can use the namespace support.\nThe following code snippet shows the available configuration options for an outbound HTTP gateway:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway id="example"\n    request-channel="requests"\n    url="http://localhost/test"\n    http-method="POST"\n    extract-request-payload="false"\n    expected-response-type="java.lang.String"\n    charset="UTF-8"\n    request-factory="requestFactory"\n    reply-timeout="1234"\n    reply-channel="replies"/>\n')])])]),a("p",[e._v("Most importantly, notice that the 'http-method' and 'expected-response-type' attributes are provided.\nThose are two of the most commonly configured values.\nThe default "),a("code",[e._v("http-method")]),e._v(" is "),a("code",[e._v("POST")]),e._v(", and the default response type is null.\nWith a null response type, the payload of the reply "),a("code",[e._v("Message")]),e._v(" contains the "),a("code",[e._v("ResponseEntity")]),e._v(", as long as its HTTP status is a success (non-successful status codes throw exceptions).\nIf you expect a different type, such as a "),a("code",[e._v("String")]),e._v(", provide that as a fully-qualified class name ("),a("code",[e._v("java.lang.String")]),e._v(" in the preceding example).\nSee also the note about empty response bodies in "),a("a",{attrs:{href:"#http-outbound"}},[e._v("HTTP Outbound Components")]),e._v(".")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Beginning with Spring Integration 2.1, the "),a("code",[e._v("request-timeout")]),e._v(" attribute of the HTTP outbound gateway was renamed to "),a("code",[e._v("reply-timeout")]),e._v(" to better reflect its intent.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("Since Spring Integration 2.2, Java serialization over HTTP is no longer enabled by default."),a("br"),e._v("Previously, when setting the "),a("code",[e._v("expected-response-type")]),e._v(" attribute to a "),a("code",[e._v("Serializable")]),e._v(" object, the "),a("code",[e._v("Accept")]),e._v(" header was not properly set up."),a("br"),e._v("Since Spring Integration 2.2, the "),a("code",[e._v("SerializingHttpMessageConverter")]),e._v(" has now been updated to set the "),a("code",[e._v("Accept")]),e._v(" header to "),a("code",[e._v("application/x-java-serialized-object")]),e._v("."),a("br"),a("br"),e._v("However, because this could cause incompatibility with existing applications, it was decided to no longer automatically add this converter to the HTTP endpoints."),a("br"),e._v("If you wish to use Java serialization, you can add the "),a("code",[e._v("SerializingHttpMessageConverter")]),e._v(" to the appropriate endpoints, by using the "),a("code",[e._v("message-converters")]),e._v(" attribute (when you use XML configuration) or by using the "),a("code",[e._v("setMessageConverters()")]),e._v(" method (in Java configuration)."),a("br"),e._v("Alternatively, you may wish to consider using JSON instead, which is enabled by having "),a("a",{attrs:{href:"https://github.com/FasterXML/jackson",target:"_blank",rel:"noopener noreferrer"}},[e._v("the Jackson library"),a("OutboundLink")],1),e._v(" on the classpath.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("Beginning with Spring Integration 2.2, you can also determine the HTTP method dynamically by using SpEL and the "),a("code",[e._v("http-method-expression")]),e._v(" attribute.\nNote that this attribute is mutually exclusive with "),a("code",[e._v("http-method")]),e._v(".\nYou can also use the "),a("code",[e._v("expected-response-type-expression")]),e._v(" attribute instead of "),a("code",[e._v("expected-response-type")]),e._v(" and provide any valid SpEL expression that determines the type of the response.\nThe following configuration example uses "),a("code",[e._v("expected-response-type-expression")]),e._v(":")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway id="example"\n    request-channel="requests"\n    url="http://localhost/test"\n    http-method-expression="headers.httpMethod"\n    extract-request-payload="false"\n    expected-response-type-expression="payload"\n    charset="UTF-8"\n    request-factory="requestFactory"\n    reply-timeout="1234"\n    reply-channel="replies"/>\n')])])]),a("p",[e._v("If your outbound adapter is to be used in a unidirectional way, you can use an "),a("code",[e._v("outbound-channel-adapter")]),e._v(" instead.\nThis means that a successful response executes without sending any messages to a reply channel.\nIn the case of any non-successful response status code, it throws an exception.\nThe configuration looks very similar to the gateway, as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-channel-adapter id="example"\n    url="http://localhost/example"\n    http-method="GET"\n    channel="requests"\n    charset="UTF-8"\n    extract-payload="false"\n    expected-response-type="java.lang.String"\n    request-factory="someRequestFactory"\n    order="3"\n    auto-startup="false"/>\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("To specify the URL, you can use either the 'url' attribute or the 'url-expression' attribute."),a("br"),e._v("The 'url' attribute takes a simple string (with placeholders for URI variables, as described below)."),a("br"),e._v("The 'url-expression' is a SpEL expression, with the "),a("code",[e._v("Message")]),e._v(" as the root object, which enables dynamic urls."),a("br"),e._v("The URL that results from the expression evaluation can still have placeholders for URI variables."),a("br"),a("br"),e._v("In previous releases, some users used the place holders to replace the entire URL with a URI variable."),a("br"),e._v("Changes in Spring 3.1 can cause some issues with escaped characters, such as '?'."),a("br"),e._v("For this reason, we recommend that, if you wish to generate the URL entirely at runtime, you use the 'url-expression' attribute.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h4",{attrs:{id:"mapping-uri-variables"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#mapping-uri-variables"}},[e._v("#")]),e._v(" Mapping URI Variables")]),e._v(" "),a("p",[e._v("If your URL contains URI variables, you can map them by using the "),a("code",[e._v("uri-variable")]),e._v(" element.\nThis element is available for the HTTP outbound gateway and the HTTP outbound channel adapter.\nThe following example maps the "),a("code",[e._v("zipCode")]),e._v(" URI variable to an expression:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway id="trafficGateway"\n    url="https://local.yahooapis.com/trafficData?appid=YdnDemo&amp;zip={zipCode}"\n    request-channel="trafficChannel"\n    http-method="GET"\n    expected-response-type="java.lang.String">\n    <int-http:uri-variable name="zipCode" expression="payload.getZip()"/>\n</int-http:outbound-gateway>\n')])])]),a("p",[e._v("The "),a("code",[e._v("uri-variable")]),e._v(" element defines two attributes: "),a("code",[e._v("name")]),e._v(" and "),a("code",[e._v("expression")]),e._v(".\nThe "),a("code",[e._v("name")]),e._v(" attribute identifies the name of the URI variable, while the "),a("code",[e._v("expression")]),e._v(" attribute is used to set the actual value.\nBy using the "),a("code",[e._v("expression")]),e._v(" 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.\nFor example, in the preceding configuration, the "),a("code",[e._v("getZip()")]),e._v(" method is invoked on the payload object of the "),a("code",[e._v("Message")]),e._v(" and the result of that method is used as the value of the URI variable named 'zipCode'.")]),e._v(" "),a("p",[e._v("Since Spring Integration 3.0, HTTP outbound endpoints support the "),a("code",[e._v("uri-variables-expression")]),e._v(" attribute to specify an "),a("code",[e._v("expression")]),e._v(" that should be evaluated, resulting in a "),a("code",[e._v("Map")]),e._v(" of all URI variable placeholders within the URL template.\nIt provides a mechanism whereby you can use different variable expressions, based on the outbound message.\nThis attribute is mutually exclusive with the "),a("code",[e._v("<uri-variable/>")]),e._v(" element.\nThe following example shows how to use the "),a("code",[e._v("uri-variables-expression")]),e._v(" attribute:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway\n     url="https://foo.host/{foo}/bars/{bar}"\n     request-channel="trafficChannel"\n     http-method="GET"\n     uri-variables-expression="@uriVariablesBean.populate(payload)"\n     expected-response-type="java.lang.String"/>\n')])])]),a("p",[a("code",[e._v("uriVariablesBean")]),e._v(" might be defined as follows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('public class UriVariablesBean {\n    private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();\n\n    public Map<String, ?> populate(Object payload) {\n        Map<String, Object> variables = new HashMap<String, Object>();\n        if (payload instanceOf String.class)) {\n            variables.put("foo", "foo"));\n        }\n        else {\n            variables.put("foo", EXPRESSION_PARSER.parseExpression("headers.bar"));\n        }\n        return variables;\n    }\n\n}\n')])])]),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("The "),a("code",[e._v("uri-variables-expression")]),e._v(" must evaluate to a "),a("code",[e._v("Map")]),e._v("."),a("br"),e._v("The values of the "),a("code",[e._v("Map")]),e._v(" must be instances of "),a("code",[e._v("String")]),e._v(" or "),a("code",[e._v("Expression")]),e._v("."),a("br"),e._v("This "),a("code",[e._v("Map")]),e._v(" is provided to an "),a("code",[e._v("ExpressionEvalMap")]),e._v(" for further resolution of URI variable placeholders by using those expressions in the context of the outbound "),a("code",[e._v("Message")]),e._v(".")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("IMPORTANT")]),e._v(" "),a("p",[e._v("The "),a("code",[e._v("uriVariablesExpression")]),e._v(" property provides a very powerful mechanism for evaluating URI variables.\nWe anticipate that people mostly use simple expressions, such as the preceding example.\nHowever, you can also configure something such as "),a("code",[e._v('"@uriVariablesBean.populate(#root)"')]),e._v(" with an expression in the returned map being "),a("code",[e._v('variables.put("thing1", EXPRESSION_PARSER.parseExpression(message.getHeaders().get("thing2", String.class)));')]),e._v(", where the expression is dynamically provided in the message header named "),a("code",[e._v("thing2")]),e._v(".\nSince the header may come from an untrusted source, the HTTP outbound endpoints use "),a("code",[e._v("SimpleEvaluationContext")]),e._v(" when evaluating these expressions.\nThe "),a("code",[e._v("SimpleEvaluationContext")]),e._v(" uses only a subset of SpEL features.\nIf you trust your message sources and wish to use the restricted SpEL constructs, set the "),a("code",[e._v("trustedSpel")]),e._v(" property of the outbound endpoint to "),a("code",[e._v("true")]),e._v(".")]),e._v(" "),a("p",[e._v("You can achieve scenarios that need to supply a dynamic set of URI variables on a per-message basis by using a custom "),a("code",[e._v("url-expression")]),e._v(" and some utilities for building and encoding URL parameters.\nThe following example shows how to do so:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("url-expression=\"T(org.springframework.web.util.UriComponentsBuilder)\n                           .fromHttpUrl('https://HOST:PORT/PATH')\n                           .queryParams(payload)\n                           .build()\n                           .toUri()\"\n")])])]),a("p",[e._v("The "),a("code",[e._v("queryParams()")]),e._v(" method expects a "),a("code",[e._v("MultiValueMap<String, String>")]),e._v(" as an argument, so you can build a real set of URL query parameters in advance, before performing the request.")]),e._v(" "),a("p",[e._v("The whole "),a("code",[e._v("queryString")]),e._v(" can also be presented as a "),a("code",[e._v("uri-variable")]),e._v(", as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway id="proxyGateway" request-channel="testChannel"\n              url="http://testServer/test?{queryString}">\n    <int-http:uri-variable name="queryString" expression="\'a=A&amp;b=B\'"/>\n</int-http:outbound-gateway>\n')])])]),a("p",[e._v("In this case, you must manually provide the URL encoding.\nFor example, you can use the "),a("code",[e._v("org.apache.http.client.utils.URLEncodedUtils#format()")]),e._v(" for this purpose.\nAs mentioned earlier, a manually built "),a("code",[e._v("MultiValueMap<String, String>")]),e._v(" can be converted to the "),a("code",[e._v("List<NameValuePair>")]),e._v(" "),a("code",[e._v("format()")]),e._v(" method argument by using the following Java Streams snippet:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("List<NameValuePair> nameValuePairs =\n    params.entrySet()\n            .stream()\n            .flatMap(e -> e\n                    .getValue()\n                    .stream()\n                    .map(v -> new BasicNameValuePair(e.getKey(), v)))\n            .collect(Collectors.toList());\n")])])]),a("h4",{attrs:{id:"controlling-uri-encoding"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#controlling-uri-encoding"}},[e._v("#")]),e._v(" Controlling URI Encoding")]),e._v(" "),a("p",[e._v("By default, the URL string is encoded (see "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("UriComponentsBuilder")]),a("OutboundLink")],1),e._v(") to the URI object before sending the request.\nIn some scenarios with a non-standard URI (such as the RabbitMQ REST API), it is undesirable to perform the encoding.\nThe "),a("code",[e._v("<http:outbound-gateway/>")]),e._v(" and "),a("code",[e._v("<http:outbound-channel-adapter/>")]),e._v(" provide an "),a("code",[e._v("encoding-mode")]),e._v(" attribute.\nTo disable encoding the URL, set this attribute to "),a("code",[e._v("NONE")]),e._v(" (by default, it is "),a("code",[e._v("TEMPLATE_AND_VALUES")]),e._v(").\nIf you wish to partially encode some of the URL, use an "),a("code",[e._v("expression")]),e._v(" within a "),a("code",[e._v("<uri-variable/>")]),e._v(", as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<http:outbound-gateway url="https://somehost/%2f/fooApps?bar={param}" encoding-mode="NONE">\n          <http:uri-variable name="param"\n            expression="T(org.apache.commons.httpclient.util.URIUtil)\n                                             .encodeWithinQuery(\'Hello World!\')"/>\n</http:outbound-gateway>\n')])])]),a("p",[e._v("With Java DSL this option can be controlled by the "),a("code",[e._v("BaseHttpMessageHandlerSpec.encodingMode()")]),e._v(" option.\nThe same configuration applies for similar outbound components in the "),a("RouterLink",{attrs:{to:"/en/spring-integration/webflux.html#webflux"}},[e._v("WebFlux module")]),e._v(" and "),a("RouterLink",{attrs:{to:"/en/spring-integration/ws.html#ws"}},[e._v("Web Services module")]),e._v(".\nFor much sophisticated scenarios it is recommended to configure an "),a("code",[e._v("UriTemplateHandler")]),e._v(" on the externally provided "),a("code",[e._v("RestTemplate")]),e._v("; or in case of WebFlux - "),a("code",[e._v("WebClient")]),e._v(" with it "),a("code",[e._v("UriBuilderFactory")]),e._v(".")],1),e._v(" "),a("h3",{attrs:{id:"configuring-http-endpoints-with-java"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#configuring-http-endpoints-with-java"}},[e._v("#")]),e._v(" Configuring HTTP Endpoints with Java")]),e._v(" "),a("p",[e._v("The following example shows how to configure an inbound gateway with Java:")]),e._v(" "),a("p",[e._v("Example 1. Inbound Gateway Using Java Configuration")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('@Bean\npublic HttpRequestHandlingMessagingGateway inbound() {\n    HttpRequestHandlingMessagingGateway gateway =\n        new HttpRequestHandlingMessagingGateway(true);\n    gateway.setRequestMapping(mapping());\n    gateway.setRequestPayloadType(String.class);\n    gateway.setRequestChannelName("httpRequest");\n    return gateway;\n}\n\n@Bean\npublic RequestMapping mapping() {\n    RequestMapping requestMapping = new RequestMapping();\n    requestMapping.setPathPatterns("/foo");\n    requestMapping.setMethods(HttpMethod.POST);\n    return requestMapping;\n}\n')])])]),a("p",[e._v("The following example shows how to configure an inbound gateway with the Java DSL:")]),e._v(" "),a("p",[e._v("Example 2. Inbound Gateway Using the Java DSL")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('@Bean\npublic IntegrationFlow inbound() {\n    return IntegrationFlows.from(Http.inboundGateway("/foo")\n            .requestMapping(m -> m.methods(HttpMethod.POST))\n            .requestPayloadType(String.class))\n        .channel("httpRequest")\n        .get();\n}\n')])])]),a("p",[e._v("The following example shows how to configure an outbound gateway with Java:")]),e._v(" "),a("p",[e._v("Example 3. Outbound Gateway Using Java Configuration")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('@ServiceActivator(inputChannel = "httpOutRequest")\n@Bean\npublic HttpRequestExecutingMessageHandler outbound() {\n    HttpRequestExecutingMessageHandler handler =\n        new HttpRequestExecutingMessageHandler("http://localhost:8080/foo");\n    handler.setHttpMethod(HttpMethod.POST);\n    handler.setExpectedResponseType(String.class);\n    return handler;\n}\n')])])]),a("p",[e._v("The following example shows how to configure an outbound gateway with the Java DSL:")]),e._v(" "),a("p",[e._v("Example 4. Outbound Gateway Using the Java DSL")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('@Bean\npublic IntegrationFlow outbound() {\n    return IntegrationFlows.from("httpOutRequest")\n        .handle(Http.outboundGateway("http://localhost:8080/foo")\n            .httpMethod(HttpMethod.POST)\n            .expectedResponseType(String.class))\n        .get();\n}\n')])])]),a("h3",{attrs:{id:"timeout-handling"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#timeout-handling"}},[e._v("#")]),e._v(" Timeout Handling")]),e._v(" "),a("p",[e._v("In the context of HTTP components, there are two timing areas that have to be considered:")]),e._v(" "),a("ul",[a("li",[a("p",[e._v("Timeouts when interacting with Spring Integration Channels")])]),e._v(" "),a("li",[a("p",[e._v("Timeouts when interacting with a remote HTTP server")])])]),e._v(" "),a("p",[e._v("The components interact with message channels, for which timeouts can be specified.\nFor example, an HTTP Inbound Gateway forwards messages received from connected HTTP Clients to a message channel (which uses a request timeout) and consequently the HTTP Inbound Gateway receives a reply message from the reply channel (which uses a reply timeout) that is used to generate the HTTP Response.\nThe following illustration offers a visual explanation:")]),e._v(" "),a("p",[a("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/http-inbound-gateway.png",alt:"http inbound gateway"}})]),e._v(" "),a("p",[e._v("Figure 1. How timeout settings apply to an HTTP Inbound Gateway")]),e._v(" "),a("p",[e._v("For outbound endpoints, we need to consider how timing works while interacting with the remote server.\nThe following image shows this scenario:")]),e._v(" "),a("p",[a("img",{attrs:{src:"https://docs.spring.io/spring-integration/docs/current/reference/html/images/http-outbound-gateway.png",alt:"http outbound gateway"}})]),e._v(" "),a("p",[e._v("Figure 2. How timeout settings apply to an HTTP Outbound Gateway")]),e._v(" "),a("p",[e._v("You may want to configure the HTTP related timeout behavior, when making active HTTP requests by using the HTTP outbound gateway or the HTTP outbound channel adapter.\nIn those instances, these two components use Spring’s "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("RestTemplate")]),a("OutboundLink")],1),e._v(" support to execute HTTP requests.")]),e._v(" "),a("p",[e._v("To configure timeouts for the HTTP outbound gateway and the HTTP outbound channel adapter, you can either reference a "),a("code",[e._v("RestTemplate")]),e._v(" bean directly (by using the "),a("code",[e._v("rest-template")]),e._v(" attribute) or you can provide a reference to a "),a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/client/ClientHttpRequestFactory.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("ClientHttpRequestFactory")]),a("OutboundLink")],1),e._v(" bean (by using the "),a("code",[e._v("request-factory")]),e._v(" attribute).\nSpring provides the following implementations of the "),a("code",[e._v("ClientHttpRequestFactory")]),e._v(" interface:")]),e._v(" "),a("ul",[a("li",[a("p",[a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/client/SimpleClientHttpRequestFactory.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("SimpleClientHttpRequestFactory")]),a("OutboundLink")],1),e._v(": Uses standard J2SE facilities for making HTTP Requests")])]),e._v(" "),a("li",[a("p",[a("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.html",target:"_blank",rel:"noopener noreferrer"}},[a("code",[e._v("HttpComponentsClientHttpRequestFactory")]),a("OutboundLink")],1),e._v(": Uses "),a("a",{attrs:{href:"https://hc.apache.org/httpcomponents-client-ga/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apache HttpComponents HttpClient"),a("OutboundLink")],1),e._v(" (since Spring 3.1)")])])]),e._v(" "),a("p",[e._v("If you do not explicitly configure the "),a("code",[e._v("request-factory")]),e._v(" or "),a("code",[e._v("rest-template")]),e._v(" attribute, a default "),a("code",[e._v("RestTemplate")]),e._v(" (which uses a "),a("code",[e._v("SimpleClientHttpRequestFactory")]),e._v(") is instantiated.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("With some JVM implementations, the handling of timeouts by the "),a("code",[e._v("URLConnection")]),e._v(" class may not be consistent."),a("br"),a("br"),e._v("For example, from the Java™ Platform, Standard Edition 6 API Specification on "),a("code",[e._v("setConnectTimeout")]),e._v(":"),a("br"),a("br"),e._v("> Some non-standard implementation of this method may ignore the specified timeout."),a("br"),e._v("> To see the connect timeout set, please call getConnectTimeout()."),a("br"),a("br"),e._v("If you have specific needs, you should test your timeouts."),a("br"),e._v("Consider using the "),a("code",[e._v("HttpComponentsClientHttpRequestFactory")]),e._v(", which, in turn, uses "),a("a",{attrs:{href:"https://hc.apache.org/httpcomponents-client-ga/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apache HttpComponents HttpClient"),a("OutboundLink")],1),e._v(" rather than relying on implementations provided by a JVM.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("When you use the Apache HttpComponents HttpClient with a pooling connection manager, you should be aware that, by default, the connection manager creates no more than two concurrent connections per given route and no more than 20 connections in total."),a("br"),e._v("For many real-world applications, these limits may prove to be too constraining."),a("br"),e._v("See the "),a("a",{attrs:{href:"https://hc.apache.org/httpcomponents-client-ga/",target:"_blank",rel:"noopener noreferrer"}},[e._v("Apache documentation"),a("OutboundLink")],1),e._v(" for information about configuring this important component.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("p",[e._v("The following example configures an HTTP outbound gateway by using a "),a("code",[e._v("SimpleClientHttpRequestFactory")]),e._v(" that is configured with connect and read timeouts of 5 seconds, respectively:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway url="https://samples.openweathermap.org/data/2.5/weather?q={city}"\n                           http-method="GET"\n                           expected-response-type="java.lang.String"\n                           request-factory="requestFactory"\n                           request-channel="requestChannel"\n                           reply-channel="replyChannel">\n    <int-http:uri-variable name="city" expression="payload"/>\n</int-http:outbound-gateway>\n\n<bean id="requestFactory"\n      class="org.springframework.http.client.SimpleClientHttpRequestFactory">\n    <property name="connectTimeout" value="5000"/>\n    <property name="readTimeout"    value="5000"/>\n</bean>\n')])])]),a("p",[a("em",[e._v("HTTP Outbound Gateway")])]),e._v(" "),a("p",[e._v("For the "),a("em",[e._v("HTTP Outbound Gateway")]),e._v(", the XML Schema defines only the "),a("em",[e._v("reply-timeout")]),e._v(".\nThe "),a("em",[e._v("reply-timeout")]),e._v(" maps to the "),a("em",[e._v("sendTimeout")]),e._v(" property of the "),a("em",[e._v("org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler")]),e._v(" class.\nMore precisely, the property is set on the extended "),a("code",[e._v("AbstractReplyProducingMessageHandler")]),e._v(" class, which ultimately sets the property on the "),a("code",[e._v("MessagingTemplate")]),e._v(".")]),e._v(" "),a("p",[e._v("The value of the "),a("em",[e._v("sendTimeout")]),e._v(' property defaults to "-1" and will be applied to the connected '),a("code",[e._v("MessageChannel")]),e._v(".\nThis means, that depending on the implementation, the Message Channel’s "),a("em",[e._v("send")]),e._v(" method may block indefinitely.\nFurthermore, the "),a("em",[e._v("sendTimeout")]),e._v(" property is only used, when the actual MessageChannel implementation has a blocking send (such as 'full' bounded QueueChannel).")]),e._v(" "),a("h4",{attrs:{id:"http-inbound-gateway"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-inbound-gateway"}},[e._v("#")]),e._v(" HTTP Inbound Gateway")]),e._v(" "),a("p",[e._v("For the HTTP inbound gateway, the XML Schema defines the "),a("code",[e._v("request-timeout")]),e._v(" attribute, which is used to set the "),a("code",[e._v("requestTimeout")]),e._v(" property on the "),a("code",[e._v("HttpRequestHandlingMessagingGateway")]),e._v(" class (on the extended "),a("code",[e._v("MessagingGatewaySupport")]),e._v(" class).\nYou can also use the "),a("code",[e._v("reply-timeout")]),e._v(" attribute to map to the "),a("code",[e._v("replyTimeout")]),e._v(" property on the same class.")]),e._v(" "),a("p",[e._v("The default for both timeout properties is "),a("code",[e._v("1000ms")]),e._v(" (one thousand milliseconds or one second).\nUltimately, the "),a("code",[e._v("request-timeout")]),e._v(" property is used to set the "),a("code",[e._v("sendTimeout")]),e._v(" on the "),a("code",[e._v("MessagingTemplate")]),e._v(" instance.\nThe "),a("code",[e._v("replyTimeout")]),e._v(" property, on the other hand, is used to set the "),a("code",[e._v("receiveTimeout")]),e._v(" property on the "),a("code",[e._v("MessagingTemplate")]),e._v(" instance.")]),e._v(" "),a("table",[a("thead",[a("tr",[a("th"),e._v(" "),a("th",[e._v("To simulate connection timeouts, you can connect to a non-routable IP address, such as 10.255.255.10.")])])]),e._v(" "),a("tbody")]),e._v(" "),a("h3",{attrs:{id:"http-proxy-configuration"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-proxy-configuration"}},[e._v("#")]),e._v(" HTTP Proxy configuration")]),e._v(" "),a("p",[e._v("If you are behind a proxy and need to configure proxy settings for HTTP outbound adapters or gateways, you can apply one of two approaches.\nIn most cases, you can rely on the standard Java system properties that control the proxy settings.\nOtherwise, you can explicitly configure a Spring bean for the HTTP client request factory instance.")]),e._v(" "),a("h4",{attrs:{id:"standard-java-proxy-configuration"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#standard-java-proxy-configuration"}},[e._v("#")]),e._v(" Standard Java Proxy configuration")]),e._v(" "),a("p",[e._v("You can set three system properties to configure the proxy settings that are used by the HTTP protocol handler:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("http.proxyHost")]),e._v(": The host name of the proxy server.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("http.proxyPort")]),e._v(": The port number (the default is "),a("code",[e._v("80")]),e._v(").")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("http.nonProxyHosts")]),e._v(": A list of hosts that should be reached directly, bypassing the proxy.\nThis is a list of patterns separated by "),a("code",[e._v("|")]),e._v(".\nThe patterns may start or end with a "),a("code",[e._v("*")]),e._v(" for wildcards.\nAny host that matches one of these patterns is reached through a direct connection instead of through a proxy.")])])]),e._v(" "),a("p",[e._v("For HTTPS, the following properties are available:")]),e._v(" "),a("ul",[a("li",[a("p",[a("code",[e._v("https.proxyHost")]),e._v(": The host name of the proxy server.")])]),e._v(" "),a("li",[a("p",[a("code",[e._v("https.proxyPort")]),e._v(": The port number, the default value being 80.")])])]),e._v(" "),a("p",[e._v("For more information, see "),a("a",{attrs:{href:"https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html"),a("OutboundLink")],1)]),e._v(" "),a("h4",{attrs:{id:"spring-s-simpleclienthttprequestfactory"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#spring-s-simpleclienthttprequestfactory"}},[e._v("#")]),e._v(" Spring’s "),a("code",[e._v("SimpleClientHttpRequestFactory")])]),e._v(" "),a("p",[e._v("If you need more explicit control over the proxy configuration, you can use Spring’s "),a("code",[e._v("SimpleClientHttpRequestFactory")]),e._v(" and configure its 'proxy' property, as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<bean id="requestFactory"\n    class="org.springframework.http.client.SimpleClientHttpRequestFactory">\n    <property name="proxy">\n        <bean id="proxy" class="java.net.Proxy">\n            <constructor-arg>\n                <util:constant static-field="java.net.Proxy.Type.HTTP"/>\n            </constructor-arg>\n            <constructor-arg>\n                <bean class="java.net.InetSocketAddress">\n                    <constructor-arg value="123.0.0.1"/>\n                    <constructor-arg value="8080"/>\n                </bean>\n            </constructor-arg>\n        </bean>\n    </property>\n</bean>\n')])])]),a("h3",{attrs:{id:"http-header-mappings"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-header-mappings"}},[e._v("#")]),e._v(" HTTP Header Mappings")]),e._v(" "),a("p",[e._v("Spring Integration provides support for HTTP header mapping for both HTTP Request and HTTP Responses.")]),e._v(" "),a("p",[e._v("By default, all standard "),a("a",{attrs:{href:"https://en.wikipedia.org/wiki/List_of_HTTP_header_fields",target:"_blank",rel:"noopener noreferrer"}},[e._v("HTTP headers"),a("OutboundLink")],1),e._v(" are mapped from the message to HTTP request or response headers without further configuration.\nHowever, if you do need further customization, you can provide additional configuration by taking advantage of the namespace support.\nYou can provide a comma-separated list of header names, and you can include simple patterns with the '*' character acting as a wildcard.\nProvide such values overrides the default behavior.\nBasically, it assumes you are in complete control at that point.\nHowever, if you do want to include all of the standard HTTP headers, you can use the shortcut patterns: "),a("code",[e._v("HTTP_REQUEST_HEADERS")]),e._v(" and "),a("code",[e._v("HTTP_RESPONSE_HEADERS")]),e._v(".\nThe following listing shows two examples (the first of which uses a wildcard):")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway id="httpGateway"\n    url="http://localhost/test2"\n    mapped-request-headers="thing1, thing2"\n    mapped-response-headers="X-*, HTTP_RESPONSE_HEADERS"\n    channel="someChannel"/>\n\n<int-http:outbound-channel-adapter id="httpAdapter"\n    url="http://localhost/test2"\n    mapped-request-headers="thing1, thing2, HTTP_REQUEST_HEADERS"\n    channel="someChannel"/>\n')])])]),a("p",[e._v("The adapters and gateways use the "),a("code",[e._v("DefaultHttpHeaderMapper")]),e._v(", which now provides two static factory methods for inbound and outbound adapters so that the proper direction can be applied (mapping HTTP requests and responses either in or out, as appropriate).")]),e._v(" "),a("p",[e._v("If you need further customization, you can also configure a "),a("code",[e._v("DefaultHttpHeaderMapper")]),e._v(" independently and inject it into the adapter through the "),a("code",[e._v("header-mapper")]),e._v(" attribute.")]),e._v(" "),a("p",[e._v("Before version 5.0, the "),a("code",[e._v("DefaultHttpHeaderMapper")]),e._v(" the default prefix for user-defined, non-standard HTTP headers was "),a("code",[e._v("X-")]),e._v(".\nVersion 5.0 changed the default prefix to an empty string.\nAccording to "),a("a",{attrs:{href:"https://tools.ietf.org/html/rfc6648",target:"_blank",rel:"noopener noreferrer"}},[e._v("RFC-6648"),a("OutboundLink")],1),e._v(", the use of such prefixes is now discouraged.\nYou can still customize this option by setting the "),a("code",[e._v("DefaultHttpHeaderMapper.setUserDefinedHeaderPrefix()")]),e._v(" property.\nThe following example configures a header mapper for an HTTP gateway:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:outbound-gateway id="httpGateway"\n    url="http://localhost/test2"\n    header-mapper="headerMapper"\n    channel="someChannel"/>\n\n<bean id="headerMapper" class="o.s.i.http.support.DefaultHttpHeaderMapper">\n    <property name="inboundHeaderNames" value="thing1*, *thing2, thing3"/>\n    <property name="outboundHeaderNames" value="a*b, d"/>\n</bean>\n')])])]),a("p",[e._v("If you need to do something other than what the "),a("code",[e._v("DefaultHttpHeaderMapper")]),e._v(" supports, you can implement the "),a("code",[e._v("HeaderMapper")]),e._v(" strategy interface directly and provide a reference to your implementation.")]),e._v(" "),a("h3",{attrs:{id:"integration-graph-controller"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#integration-graph-controller"}},[e._v("#")]),e._v(" Integration Graph Controller")]),e._v(" "),a("p",[e._v("Starting with version 4.3, the HTTP module provides an "),a("code",[e._v("@EnableIntegrationGraphController")]),e._v(" configuration class annotation and an "),a("code",[e._v("<int-http:graph-controller/>")]),e._v(" XML element to expose the "),a("code",[e._v("IntegrationGraphServer")]),e._v(" as a REST service.\nSee "),a("RouterLink",{attrs:{to:"/en/spring-integration/graph.html#integration-graph"}},[e._v("Integration Graph")]),e._v(" for more information.")],1),e._v(" "),a("h3",{attrs:{id:"http-samples"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#http-samples"}},[e._v("#")]),e._v(" HTTP Samples")]),e._v(" "),a("p",[e._v("This section wraps up our coverage of Spring Integration’s HTTP support with a few examples.")]),e._v(" "),a("h4",{attrs:{id:""}},[a("a",{staticClass:"header-anchor",attrs:{href:"#"}},[e._v("#")])]),e._v(" "),a("p",[e._v("This example shows how simple it is to send a multipart HTTP request with Spring’s "),a("code",[e._v("RestTemplate")]),e._v(" and receive it with a Spring Integration HTTP inbound adapter.\nWe create a "),a("code",[e._v("MultiValueMap")]),e._v(" and populate it with multipart data.\nThe "),a("code",[e._v("RestTemplate")]),e._v(" takes care of the rest (no pun intended) by converting it to a "),a("code",[e._v("MultipartHttpServletRequest")]),e._v(".\nThis particular client sends a multipart HTTP Request that contains the name of the company and an image file (the company logo).\nThe following listing shows the example:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('RestTemplate template = new RestTemplate();\nString uri = "http://localhost:8080/multipart-http/inboundAdapter.htm";\nResource s2logo =\n   new ClassPathResource("org/springframework/samples/multipart/spring09_logo.png");\nMultiValueMap map = new LinkedMultiValueMap();\nmap.add("company", "SpringSource");\nmap.add("company-logo", s2logo);\nHttpHeaders headers = new HttpHeaders();\nheaders.setContentType(new MediaType("multipart", "form-data"));\nHttpEntity request = new HttpEntity(map, headers);\nResponseEntity<?> httpResponse = template.exchange(uri, HttpMethod.POST, request, null);\n')])])]),a("p",[e._v("That is all we need for the client.")]),e._v(" "),a("p",[e._v("On the server side, we have the following configuration:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('<int-http:inbound-channel-adapter id="httpInboundAdapter"\n    channel="receiveChannel"\n    path="/inboundAdapter.htm"\n    supported-methods="GET, POST"/>\n\n<int:channel id="receiveChannel"/>\n\n<int:service-activator input-channel="receiveChannel">\n    <bean class="org.springframework.integration.samples.multipart.MultipartReceiver"/>\n</int:service-activator>\n\n<bean id="multipartResolver"\n    class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>\n')])])]),a("p",[e._v("The 'httpInboundAdapter' receives the request and converts it to a "),a("code",[e._v("Message")]),e._v(" with a payload that is a "),a("code",[e._v("LinkedMultiValueMap")]),e._v(".\nWe then parse that in the 'multipartReceiver' service-activator, as the following example shows:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v('public void receive(LinkedMultiValueMap<String, Object> multipartRequest){\n    System.out.println("### Successfully received multipart request ###");\n    for (String elementName : multipartRequest.keySet()) {\n        if (elementName.equals("company")){\n            System.out.println("\\t" + elementName + " - " +\n                ((String[]) multipartRequest.getFirst("company"))[0]);\n        }\n        else if (elementName.equals("company-logo")){\n            System.out.println("\\t" + elementName + " - as UploadedMultipartFile: " +\n                ((UploadedMultipartFile) multipartRequest\n                    .getFirst("company-logo")).getOriginalFilename());\n        }\n    }\n}\n')])])]),a("p",[e._v("You should see the following output:")]),e._v(" "),a("div",{staticClass:"language- extra-class"},[a("pre",{pre:!0,attrs:{class:"language-text"}},[a("code",[e._v("### Successfully received multipart request ###\n   company - SpringSource\n   company-logo - as UploadedMultipartFile: spring09_logo.png\n")])])])])}),[],!1,null,null,null);t.default=o.exports}}]);