Spring 框架接收GZIP个数数据处理
Spring 框架接收GZIP个数数据处理
问题描述
上次处理了Feign的GZIP压缩问题,遇到了一个新的问题
经过了Feign转发一次后,请求的数据经过GZIP压缩了一次
有出现了一下错误信息
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens; 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
这就说明了spring没有默认支持GZIP格式的解压缩
处理方式如下
package com.test.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* 处理Gzip
* @author Wei
* @date 2022/11/16 9:43
*/
@Configuration
public class FilterConfig {
/**
* 注册 GzipFilter
*
* @return
*/
@Bean
public FilterRegistrationBean<Filter> filterRegistrationBean() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new GzipFilterConfig());
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/*");
registrationBean.setUrlPatterns(urlPatterns);
return registrationBean;
}
@WebFilter(filterName = "gzipFilter", urlPatterns = "/")
public static class GzipFilterConfig implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request), response);
}
@Override
public void init(javax.servlet.FilterConfig arg0){
}
}
@Slf4j
static class HttpServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper {
private final HttpServletRequest request;
public HttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 根据 request header 的 Content-Encoding 判断是否启用 gzip 解压数据流
*/
@Override
public ServletInputStream getInputStream() throws IOException {
ServletInputStream stream = request.getInputStream();
String contentEncoding = request.getHeader("Content-Encoding");
if (null != contentEncoding && contentEncoding.contains("gzip")) {
GZIPInputStream gzipInputStream = new GZIPInputStream(stream);
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int len = -1;
byte[] buffer = new byte[128];
while((len = gzipInputStream.read(buffer))!=-1){
bout.write(buffer, 0, len);
}
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
return new ServletInputStream() {
@Override
public int read(){
return bin.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
} catch (Exception e) {
log.error("decompression content fail", e);
}finally{
try {
gzipInputStream.close();
} catch (Exception e) {
//
}
}
}
return stream;
}
}
}