我正在使用春季假装来压缩请求和响应
在服务器端:
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”作为两个不同的值发送]
让我知道这里是否有问题
这实际上是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
几周前,我也面临着同样的问题,我知道这样做并没有卓有成效/直截了当的方法。我还知道,当@patan向spring社区@patan reported issue1和@patan reported issue2报告该问题时,已经为雄猫一方创建了一张票证,试图解决此问题(issue link)。在码头一侧也有与此相关的票证(ticket link)。最初,我计划使用github中建议的方法,但后来知道该库已经合并到spring-cloud-openfeign-core
包下的org.springframework.cloud.openfeign.encoding
jar中。然而,我们无法实现预期的压缩,并且面临以下两个挑战: