0
votes

I'm trying to pass some custom HTTP headers using <int-http:outbound-gateway> and <int:header-enricher> components of Spring Integration, but it doesn't work on my configuration.

I have tried two configurations. The first one with the "mapped-request-headers" attribute:

<int:chain input-channel="requestChannel" output-channel="replyChannel">
    <int:header-enricher>
        <int:header name="test" value="test"></int:header>
    </int:header-enricher>
    <int-http:outbound-gateway id="gateway"
        encode-uri="true" url="http://localhost:8080/webapp/service/{request}"
        http-method="GET" mapped-request-headers="test, HTTP_REQUEST_HEADERS">
        <int-http:uri-variable name="request" expression="payload"/>
    </int-http:outbound-gateway>
</int:chain>

The second one with the "header-mapper" attribute, with the relative DefaultHttpHeaderMapper configuration:

<int:chain input-channel="requestChannel" output-channel="replyChannel">
    <int:header-enricher>
        <int:header name="test" value="test"></int:header>
    </int:header-enricher>
    <int-http:outbound-gateway id="gateway"
        encode-uri="true" url="http://localhost:8080/webapp/service/{request}"
        http-method="GET" header-mapper="headerMapper">
        <int-http:uri-variable name="request" expression="payload"/>
    </int-http:outbound-gateway>
</int:chain>

<bean id="headerMapper" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
    <property name="outboundHeaderNames" value="HTTP_REQUEST_HEADERS, test" />
    <property name="userDefinedHeaderPrefix" value="" />
</bean>

But in both cases, the message's headers loaded by the remote application are the following:

GenericMessage[
    payload={},
    headers={
        http_requestMethod=GET,
        replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@4c8b7a27,
        errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@4c8b7a27,
        host=localhost: 8080,
        http_requestUrl=http://localhost:8080/webapp/service/hello,
        connection=keep-alive,
        id=3c2a21ba-b7f5-e5e9-c821-45251d406318,
        cache-control=no-cache,
        pragma=no-cache,
        user-agent=Java/1.8.0_65,
        accept=[
            text/html,
            image/gif,
            image/jpeg,
            */*;q=.2,
            */*;q=.2],
        timestamp=1469009855797
    }
]

There is no trace of the "test" header that I'm trying to add to the request message.

What's the right way to add a custom header to the <int-http:outbound-gateway> ?

It's also good any other working solution.

UPDATE

As from Gary indication, I turned on the DEBUG mode.

This is a very interesting thing: the log says that the header [test] "will be mapped":

message sent: GenericMessage [payload=hello, headers={id=79f98422-418b-f00f-1e21-09461b1ff80c, timestamp=1469021452494}]
2016-07-20 15:53:57 DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper.fromHeaders:402 (executor-4) - outboundHeaderNames=[test, HTTP_REQUEST_HEADERS]
2016-07-20 15:53:57 DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:537 (executor-4) - headerName=[test] WILL be mapped, matched pattern=test
2016-07-20 15:53:57 DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper.fromHeaders:420 (executor-4) - setting headerName=[X-test], value=test
2016-07-20 15:53:57 DEBUG org.springframework.http.client.support.HttpAccessor.createRequest:79 (executor-4) - Created GET request for "http://localhost:8080/webapp/service/hello"

I have implemented a simple Filter on the server side that intercepts every HTTP request, and it prints on the log every header of that request.

This is the result:

x-test=test
cache-control=no-cache
pragma=no-cache
user-agent=Java/1.8.0_65
host=localhost:8080
accept=text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
connection=keep-alive

So, the header "x-test" is present on the HttpServletRequest instance.

But after that, in the log I can see this other message (I have reported only those significant for this context):

2016-07-20 15:53:57 DEBUG org.springframework.web.servlet.DispatcherServlet.doService:865 (http-nio-8080-exec-1) - DispatcherServlet with name 'dispatcherServer' processing GET request for [/webapp/service/hello]
2016-07-20 15:53:57 DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper.toHeaders:436 (http-nio-8080-exec-1) - inboundHeaderNames=[Accept, Accept-Charset, Accept-Encoding, Accept-Language, Accept-Ranges, Authorization, Cache-Control, Connection, Content-Length, Content-Type, Cookie, Date, Expect, From, Host, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Max-Forwards, Pragma, Proxy-Authorization, Range, Referer, TE, Upgrade, User-Agent, Via, Warning]
2016-07-20 15:53:57 DEBUG org.springframework.integration.http.support.DefaultHttpHeaderMapper.shouldMapHeader:561 (http-nio-8080-exec-1) - headerName=[x-test] WILL NOT be mapped
2016-07-20 15:53:57 DEBUG org.springframework.integration.handler.AbstractMessageHandler.handleMessage:115 (executor-4) - ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor@6ae60a] (channelServiceActivator) received message: GenericMessage [payload={}, headers={http_requestMethod=GET, replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@565fe0d8, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@565fe0d8, host=localhost:8080, http_requestUrl=http://localhost:8080/webapp/service/hello, connection=keep-alive, id=9578f82d-7fc2-fe94-d8bf-3225ec955b22, cache-control=no-cache, pragma=no-cache, user-agent=Java/1.8.0_65, accept=[text/html, image/gif, image/jpeg, */*;q=.2, */*;q=.2], timestamp=1469022837172}]

Now the log says that the header "[x-test] WILL NOT be mapped". How is possibile? It's because it doesn't appear in the inboundHeaderNames ?

In fact, the header seems to be "disappeared" in the GenericMessage:

GenericMessage [
    payload={}, 
    headers={
        http_requestMethod=GET,
        replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@16b10fb6,
        errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@16b10fb6,
        host=localhost:8080,
        http_requestUrl=http://localhost:8080/webapp/service/hello,
        connection=keep-alive,
        id=ba2af515-9e29-4d84-d176-5b9d0d066cb0,
        cache-control=no-cache,
        pragma=no-cache,
        user-agent=Java/1.8.0_65,
        accept=[text/html,
            image/gif,
            image/jpeg,
            */*;q=.2,
            */*;q=.2],
        timestamp=1469021452542
    }
]

I don't understand why the header in present in the HTTP Request, but it's no present in the headers of the Message channel.

2

2 Answers

3
votes

I have found the answer for this issue.

The <int-http:outbound-gateway> maps the headers that had to be inserted in the "exiting" HTTP requests.

The <int-http:inbound-gateway> maps the headers that are contained in the "entering" HTTP requests.

So, it has to be defined a "header-mapper" that:

  • maps the "inboundHeaderNames" for the <int-http:inbound-gateway>
  • maps the "outboundHeaderNames" for the <int-http:outbound-gateway>

In my example case, the solution for the "OUTBOUND SIDE" (the client application) was:

<int:chain input-channel="requestChannel" output-channel="replyChannel">
    <int:header-enricher>
        <int:header name="test" value="test"></int:header>
    </int:header-enricher>
    <int-http:outbound-gateway id="gateway"
        encode-uri="true" url="http://localhost:8080/webapp/service/{request}"
        http-method="GET" header-mapper="headerMapper">
        <int-http:uri-variable name="request" expression="payload"/>
    </int-http:outbound-gateway>
</int:chain>

<bean id="headerMapper" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
    <property name="outboundHeaderNames" value="HTTP_REQUEST_HEADERS, test" />
    <property name="userDefinedHeaderPrefix" value="" />
</bean>

The "outboundHeaderNames" has to be setted with the header names that has to be mapped in the "outbound requests" ("test" in this case).

While the solution for the "INBOUND SIDE" (the receiver application) was:

<int-http:inbound-gateway id="gateway" request-channel="requestChannel"
      path="/service/**" supported-methods="GET"
      reply-channel="outputChannel" header-mapper="headerMapper">
</int-http:inbound-gateway>

<bean id="headerMapper" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
    <property name="inboundHeaderNames" value="*" />
</bean>

The "inboundHeaderNames" setted to "*" ensure that all the headers of the source request will be mapped in the Message headers.

With this approach, we can pass custom headers to any URL in HTTP requests, and we can recover them on the server side in the message channel context.

0
votes

Turn on DEBUG logging; you should see messages about header mapping like this...

08:46:44.987 DEBUG [main] ... headerName=[id] WILL NOT be mapped

08:46:44.987 DEBUG [main] ... headerName=[test] WILL be mapped, matched pattern=test

08:46:44.987 DEBUG [main] ... setting headerName=[X-test], value=foo

(This is with your first example - custom headers currently get the X- prefix by default).