Spring Feign不压缩响应

问题描述 投票:0回答:2

我正在使用春季假装来压缩请求和响应

在服务器端:

server:
  servlet:
    context-path: /api/v1/
  compression:
    enabled: true
    min-response-size: 1024

[当我从Chrome浏览器访问api时,我看到它添加了'Accept-Encoding': "gzip, deflate, br"

在客户端:

    server:
      port: 8192
      servlet:
        context-path: /api/demo



feign.compression.response.enabled: true

feign.client.config.default.loggerLevel: HEADERS

logging.level.com.example.feigndemo.ManagementApiService: DEBUG

eureka:
  client:
    enabled: false

management-api:
  ribbon:
    listOfServers: localhost:8080

[当我看到请求标头通过时,假装正在传递两个标头。

Accept-Encoding: deflate
Accept-Encoding: gzip

毕业文件

plugins {
        id 'org.springframework.boot' version '2.1.8.RELEASE'
        id 'io.spring.dependency-management' version '1.0.8.RELEASE'
        id 'java'
    }

    group = 'com.example'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '1.8'

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    repositories {
        mavenCentral()
    }

    ext {
        set('springCloudVersion', "Greenwich.SR2")
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        compile ('org.springframework.cloud:spring-cloud-starter-netflix-ribbon')
        compile('org.springframework.cloud:spring-cloud-starter-openfeign')
    // https://mvnrepository.com/artifact/io.github.openfeign/feign-httpclient
    // https://mvnrepository.com/artifact/io.github.openfeign/feign-httpclient
        //compile group: 'io.github.openfeign', name: 'feign-httpclient', version: '9.5.0'

        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
    }

    dependencyManagement {
        imports {
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        }
    }

响应未压缩。我所看到的是,Spring feign正在将“ Accept-Encoding”作为两个不同的值发送]

让我知道这里是否有问题

spring spring-boot spring-cloud-feign
2个回答
0
投票

这实际上是Tomcat和Jetty的一个例外-上面给出的多个编码标头是合法的,应该可以使用,但是Tomcat和Jetty的一个错误会阻止它们同时读取。

该错误已在spring boot github here中报告。并在tomcat here中供参考。

[在Tomcat中,此问题已在9.0.25中修复,因此,如果可以对此进行更新,则可以解决。失败了,这是您可以解决的解决方法:

您将需要创建自己的请求拦截器来协调您的gzip,将标头压缩为单个标头。

此拦截器需要添加到FeignClient配置中,并且该配置已添加到您的feign客户端中。

import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.template.HeaderTemplate;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

/**
 * This is a workaround interceptor based on a known bug in Tomcat and Jetty where
 * the requests are unable to perform gzip compression if the headers are in collection format.
 * This is fixed in tomcat 9.0.25 - once we reach this version we can remove this class
 */
@Slf4j
public class GzipRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // don't add encoding to all requests - only to the ones with the incorrect header format
        if (requestHasDualEncodingHeaders(template)) {
            replaceTemplateHeader(template, "Accept-Encoding", Collections.singletonList("gzip,deflate"));
        }
    }

    private boolean requestHasDualEncodingHeaders(RequestTemplate template) {
        return template.headers().get("Accept-Encoding").contains("deflate")
                && template.headers().get("Accept-Encoding").contains("gzip");
    }

    /** Because request template is immutable, we have to do some workarounds to get to the headers */
    private void replaceTemplateHeader(RequestTemplate template, String key, Collection<String> value) {
        try {
            Field headerField = RequestTemplate.class.getDeclaredField("headers");
            headerField.setAccessible(true);
            ((Map)headerField.get(template)).remove(key);
            HeaderTemplate newEncodingHeaderTemplate = HeaderTemplate.create(key, value);
            ((Map)headerField.get(template)).put(key, newEncodingHeaderTemplate);
        } catch (NoSuchFieldException e) {
            LOGGER.error("exception when trying to access the field [headers] via reflection");
        } catch (IllegalAccessException e) {
            LOGGER.error("exception when trying to get properties from the template headers");
        }
    }
}

[我知道上面的代码看起来有些矫kill过正,但是由于模板头是unmodifiable,因此我们仅需进行一些反射即可将其修改为所需的样式。

将上述拦截器添加到您的配置bean中

import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignGzipEncodingConfiguration {

    @Bean
    public RequestInterceptor gzipRequestInterceptor() {

        return new GzipRequestInterceptor();
    }
}

您最终可以使用配置注释参数将其添加到您的伪装客户端中>

@FeignClient(name = "feign-client", configuration = FeignGzipEncodingConfiguration.class)
public interface FeignClient {
    ...
}

现在,当您发送伪装的客户请求获取压缩信息时,应该会点击请求拦截器。这将擦除双头文件,并以gzip,deflate

的形式写入一个可接受的字符串,并将其连接起来

0
投票

几周前,我也面临着同样的问题,我知道这样做并没有卓有成效/直截了当的方法。我还知道,当@patan向spring社区@patan reported issue1@patan reported issue2报告该问题时,已经为雄猫一方创建了一张票证,试图解决此问题(issue link)。在码头一侧也有与此相关的票证(ticket link)。最初,我计划使用github中建议的方法,但后来知道该库已经合并到spring-cloud-openfeign-core包下的org.springframework.cloud.openfeign.encoding jar中。然而,我们无法实现预期的压缩,并且面临以下两个挑战:

© www.soinside.com 2019 - 2024. All rights reserved.