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

How can I expose the "Content-Disposition" in spring-integration (DSL)?


For downloading a file I will add the "Content-Disposition" to my responseHeader but it doesn't work.

The response will not have any added properties.

    @Bean
    public ExpressionParser fileParser() {
        return new SpelExpressionParser();
    }

    @Bean
    public HeaderMapper<HttpHeaders> fileHeaderMapper() {
        return new DefaultHttpHeaderMapper();
    }
@Bean
    public IntegrationFlow httpGetFileDownload() {
        return IntegrationFlows.from(
                Http.inboundGateway("/api/files/download/{id}")
                        .requestMapping(r -> r.methods(HttpMethod.GET))
                        .statusCodeExpression(fileParser().parseExpression("T(org.springframework.http.HttpStatus).BAD_REQUEST"))
                        .payloadExpression(fileParser().parseExpression("#pathVariables.id"))
                        .crossOrigin(cors -> cors.origin("*").exposedHeaders("Content-Disposition", "content-disposition"))
                        .headerMapper(fileHeaderMapper())
                )
                .channel("http.file.download.channel")
                .handle("fileEndpoint", "download")
                .get();
    }



public Message<?> download(Message<Long> msg){
...

return MessageBuilder
                    .withPayload(resource)
                    .copyHeaders(msg.getHeaders())
                    .setHeader(STATUSCODE_HEADER, HttpStatus.OK)
                    .setHeader(HttpHeaders.CONTENT_DISPOSITION,"attachment;filename=" + file.getName())
                    .setHeader(HttpHeaders.CONTENT_TYPE, mimeType)
                    .setHeader(HttpHeaders.CONTENT_LENGTH, (int)file.length())
                    .build();
}


What I get:

cache-control: "no-cache, no-store, max-age=0, must-revalidate"
content-type: "application/json"
expires: "0"
pragma: "no-cache"


Solution

  • Your problem that DefaultHttpHeaderMapper is empty by default. I think it might be a time to make the ctor as deprecated to not allow to use it from end application. Or to make some validation to reject just empty (not configured) DefaultHttpHeaderMapper...

    It is also confusing what is the point to use that return new DefaultHttpHeaderMapper(); if your don't customize it. There is a default one in the HttpRequestHandlingMessagingGateway:

    private HeaderMapper<HttpHeaders> headerMapper = DefaultHttpHeaderMapper.inboundMapper();
    

    To fix your problem you definitely need to use this inboundMapper() factory method, which does this:

    /**
     * Factory method for creating a basic inbound mapper instance.
     * This will map all standard HTTP request headers when receiving an HTTP request,
     * and it will map all standard HTTP response headers when sending an HTTP response.
     * @return The default inbound mapper.
     */
    public static DefaultHttpHeaderMapper inboundMapper() {
        DefaultHttpHeaderMapper mapper = new DefaultHttpHeaderMapper();
        setupDefaultInboundMapper(mapper);
        return mapper;
    }
    

    That setupDefaultInboundMapper() is very important: it brings for us a set of headers to map from the request and into response.