本文最后更新于:3 天前
Spring多次request.getReader()以及乱码问题解决方法
Spring多次request.getReader()
ServletRequest
的getReader
和getInputStream
只能调用一次
开发中遇到一个需求,在拦截器中拦截前端body里传过来的token并解析存入ThreadLocal中,方便使用,但是前端传过来的数据带有\
,一般解析不到参数,也需要获取body中的数据将\
去掉,才能转成对象。
但是,使用@RequestBody报错,因为getReader
和getInputStream
只能调用一次,要解决这个问题则需要将服务器创建的request再次封装,使之可以多次调用getReader
和getInputStream
多方查找发现Spring自带了一个对HttpServletRequestWrapper
的重写
1、继承HttpServletRequestWrapper
封装 request请求,将body中的数据保存在 byte[] body
中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| import org.apache.commons.lang3.StringUtils;
import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets;
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); BufferedReader br = null; try { try { br = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8)); } catch (IOException e) { e.printStackTrace(); } String str; StringBuilder wholeStr = new StringBuilder(); while ((str = br.readLine()) != null) { wholeStr.append(str); } if (StringUtils.isNotEmpty(wholeStr.toString())) { body = wholeStr.toString().getBytes(StandardCharsets.UTF_8); } } catch (IOException e) { e.printStackTrace(); } }
@Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); }
@Override public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override public int read() throws IOException { return bais.read(); }
@Override public boolean isFinished() { return false; }
@Override public boolean isReady() { return false; }
@Override public void setReadListener(ReadListener readListener) {
}
}; }
public void setInputStream(byte[] body) { this.body = body; } }
|
2、编写过滤器并使用注解使之生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import com.ucdt.aftersale.util.BodyReaderHttpServletRequestWrapper; import lombok.extern.slf4j.Slf4j;
import javax.servlet.FilterConfig; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException;
@Slf4j @WebFilter(filterName = "RequestWrapperFilter", urlPatterns = "/sys/*") public class RequestWrapperFilter implements Filter {
@Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); }
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest) { requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request); } if (null == requestWrapper) { log.error("过滤器包装request失败!将返回原来的request"); chain.doFilter(request, response); } else { log.info("过滤器包装request成功"); chain.doFilter(requestWrapper, response); } }
@Override public void destroy() { Filter.super.destroy(); } }
|
解决乱码问题
当在封装request请求的时候,读取中文时,会出现报错
java.nio.charset.MalformedInputException: Input length = 1
是因为字符编码的问题,在读取request输入流的时候指定字符集则可以解决。
BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8));