Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feign Content-Encoding gzip, deflate not supported #489

Closed
jmnarloch opened this issue Aug 17, 2015 · 4 comments
Closed

Feign Content-Encoding gzip, deflate not supported #489

jmnarloch opened this issue Aug 17, 2015 · 4 comments

Comments

@jmnarloch
Copy link
Contributor

Enabling Accept-Encoding: gzip, deflate through custom Feign RequestInterceptor on the outgoing requests ends with exception when the response is compressed (or in other word the payload is content encoded):

Could not read document: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]
feign.codec.DecodeException: Could not read document: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]
    at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:150)
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:118)
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:71)
    at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:94)
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:224)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:208)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:96)
    at org.springframework.cloud.netflix.feign.support.SpringDecoder.decode(SpringDecoder.java:57)
    at org.springframework.cloud.netflix.feign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:40)
    at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:146)
    ... 4 more
Caused by: com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens
 at [Source: java.io.PushbackInputStream@7169c7d4; line: 1, column: 2]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1576)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:533)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._throwInvalidSpace(ParserMinimalBase.java:484)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._skipWSOrEnd(UTF8StreamJsonParser.java:2872)
    at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:692)
    at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3742)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3687)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:221)
    ... 9 more

Tested with Undertow and Jetty GzipFilter. Spring Cloud version is 1.0.3.RELEASE

This is interesting behaviour since Feign internally can handle content encoding: https://github.com/Netflix/feign/blob/91e4d8209a0023b33e34c374c78a7c388870053e/core/src/main/java/feign/Client.java#L109

@jmnarloch jmnarloch changed the title Feign Accept-Encoding gzip, deflate Feign Accept-Encoding gzip, deflate not supported Aug 17, 2015
@jmnarloch
Copy link
Contributor Author

For testing purpose you can use this classes:

public class GzipFeignRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {

        template.header("Accept-Encoding", "gzip", "deflate");
    }
}

@Configuration
public class FeignGzipEncodingConfiguration {

    @Bean
    public RequestInterceptor gzipFeignRequestInterceptor() {

        return new GzipFeignRequestInterceptor();
    }
}

@Import(FeignGzipEncodingConfiguration.class)
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableFeignGzipEncoding {
}

@jmnarloch
Copy link
Contributor Author

Interesting, I can not reproduce this at master only in version 1.0.3-RELEASE

@jmnarloch jmnarloch changed the title Feign Accept-Encoding gzip, deflate not supported Feign Content-Encoding gzip, deflate not supported Aug 18, 2015
@jmnarloch
Copy link
Contributor Author

I think that I have figure out why it doesn't work, when used with version 1.0.3 the response body is wrapped in something like URLConnection internalls (based on what I have found after debuging), while with latest 1.1.0 snapshot when the ApacheHttpClient is enabled it's in fact org.apache.http.client.entity.DecompressingEntity populated by feign ApacheClient.

So my believe is that when fallowing code snipet would be added to version 1.0.3:

@Configuration
    @ConditionalOnClass(ApacheHttpClient.class)
    protected static class HttpClientConfiguration {

        @Autowired(required = false)
        private HttpClient httpClient;

        @ConditionalOnMissingBean
        public Client feignClient() {
            if (httpClient != null) {
                return new ApacheHttpClient(httpClient);
            }
            return new ApacheHttpClient();
        }
    }

This should work as a charm.

@jmnarloch
Copy link
Contributor Author

I was missing one extra piece I had to also add the Ribbon HttpClient configuration. After that I was able to make that work in version 1.0.3. It works out of the box in 1.1.0

Leaving the gist: https://gist.github.com/jmnarloch/2ea0efbc292fd240096f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant