Search code examples
spring-integrationspring-integration-dslspring-integration-http

Spring Integration HTTP Outbound Gateway header not forwarder on a consecutive request


I'm struggling with the following flow:

.enrichHeaders(h -> h.headerFunction("ocp-apim-subscription-key", m ->
        "xxx"))
.handle(Http.outboundGateway("https://northeurope.api.cognitive.microsoft.com/vision/v3" +
        ".0/read/analyzeResults/abc")
        .mappedRequestHeaders("ocp-apim-subscription-key")
        .httpMethod(HttpMethod.GET))
.enrichHeaders(h -> h.headerFunction("ocp-apim-subscription-key", m ->
        "xxx"))
.handle(Http.outboundGateway("https://northeurope.api.cognitive.microsoft.com/vision/v3" +
        ".0/read/analyzeResults/def")
        .mappedRequestHeaders("ocp-apim-subscription-key")
        .httpMethod(HttpMethod.GET))

The first request is submitted correctly and I get the result, for the second one I get 401 UNAUTHORIZED which means, the ocp-apim-subscription-key is not included. I've tried without the second enrichment step as I thought that the headers won't be cleared but it also didn't change anything.

Any idea what I might be doing wrong? Do I need to configure the header mapper somehow differently?

Here is the output of the debug which clearly shows that the header is included:

17:45:31.468 [main] DEBUG org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler - bean 'ocrDocument.http:outbound-gateway#2' for component 'ocrDocument.org.springframework.integration.config.ConsumerEndpointFactoryBean#3'; defined in: 'processing.OCRIntegrationFlow'; from source: 'bean method ocrDocument' received message: GenericMessage [payload=<200,[Transfer-Encoding:"chunked", Content-Type:"application/json; charset=utf-8", x-envoy-upstream-service-time:"25", CSP-Billing-Usage:"CognitiveServices.ComputerVision.Transaction=1", Strict-Transport-Security:"max-age=31536000; includeSubDomains; preload", x-content-type-options:"nosniff", Date:"Mon, 31 Aug 2020 15:45:31 GMT"]>, headers={Transfer-Encoding=chunked, ocp-apim-subscription-key=xxx, id=11fa4a77-d97a-772b-69b6-059de29ef808, contentType=application/json;charset=utf-8, http_statusCode=200 OK, Date=1598888731000, timestamp=1598888731467}]

UPDATE I've recorded a session with wireshark (switched to http instead of https as I couldn't get it to work). It seems that in the second request the subscription-key isn't propagated. For some reason in the second one more headers are included.

First one

enter image description here

Second one

enter image description here


Solution

  • OK. I see where is the problem:

    private HttpEntity<?> createHttpEntityFromPayload(Message<?> message, HttpMethod httpMethod) {
    Object payload = message.getPayload();
    if (payload instanceof HttpEntity<?>) {
        // payload is already an HttpEntity, just return it as-is
        return (HttpEntity<?>) payload;
    }
    HttpHeaders httpHeaders = mapHeaders(message);
    

    Since you propagate a ResponseEntity from the first call to the second one, there is indeed no any headers mapping since we just don't do that logic in the AbstractHttpRequestExecutingMessageHandler and use the provided HttpEntity as is.

    We can't make an assumption what you would like to do with that, but since you have provided the whole entity, we just don't mutate it and perform request against it as is.

    To fix the problem I suggest to include before second call some simple .transform((p) -> "") to avoid some HTTP entity assumption.

    And yes, you don't need the second header enricher if the value for the ocp-apim-subscription-key is the same.

    We probably need to improve docs on the matter and explain how request message is handled in this component. Feel free to raise a GH issue!