背景
由于项目需要用到拦截器验证用户的Token,但是实际结果如下:
拦截器读取HttpServletRequest输入流之后Controller再次读取就获取不到输入流了。
原因
HttpServletRequest提供了getInputStream()的方法来获取一个输入流(InputStream对象)。InputStream内部的read()函数返回值说明:
就是说有一个下标position记录了当前读取到的位置,如果一个输入流被读取完后position会被置为-1然后返回。然后还提供了一个reset()方法从注释中可以知道这个方法可以重置position的位置。
但是需要markSupported()方法返回true才可以。然而在InputStream内并没有真正实现rest()方法,markSupported()方法返回的值也是为false。这就导致了HttpServletRequest输入流只能读取一次。
解决方案
我们可以重写HttpServletRequestWrapper,然后添加过滤器解决。
BodyReaderHttpServletRequestWrapper.java
package com.demo.demo.config.Filter;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
/**
* @Classname BodyReaderHttpServletRequestWrapper
* @Description TODO
* @Date 2019/12/19 16:11
* @Created by Alienworm
*/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body; // 报文
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = InputStreamToByte(request.getInputStream());
}
private byte[] InputStreamToByte(InputStream is) throws IOException {
ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int ch;
while ((ch = is.read(buffer)) != -1)
bytestream.write(buffer, 0, ch);
byte[] data = bytestream.toByteArray();
bytestream.close();
return data;
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() { return false; }
@Override
public boolean isReady() { return false; }
@Override
public void setReadListener(ReadListener readListener) { }
@Override
public int read() { return bais.read(); }
};
}
}
BodyReaderHttpServletRequestFilter.java
package com.demo.demo.config.Filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
/**
* @Classname BodyReaderHttpServletRequestFilter
* @Description TODO
* @Date 2019/12/19 16:11
* @Created by Alienworm
*/
@WebFilter(filterName="bodyReaderHttpServletRequestFilter", urlPatterns="/*")
public final class BodyReaderHttpServletRequestFilter extends HttpFilter {
@Override
public void destroy() { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
InputStream inputStream = request.getInputStream();
BodyReaderHttpServletRequestWrapper requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest)request);
chain.doFilter(requestWrapper, response);
}
@Override
public void init(FilterConfig filterConfig) { }
}
在SpringBoot启动类里添加过滤器
DemoApplication.java
package com.demo.demo;
import com.demo.demo.config.Filter.BodyReaderHttpServletRequestFilter;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@MapperScan("com.demo.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public FilterRegistrationBean Filters() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new BodyReaderHttpServletRequestFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("BodyReaderHttpServletRequestFilter");
return registrationBean;
}
}
最后把HttpServletRequest转换成JSONObject
RequestUtil.java
package com.demo.demo.util;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.*;
import java.util.Enumeration;
import java.util.stream.Stream;
/**
* @Classname RequestUtil
* @Description TODO
* @Date 2019/12/15 00:53
* @Created by Alienworm
*/
@Slf4j
@SuppressWarnings("ALL")
public class RequestUtil {
// 客户端请求
private static HttpServletRequest httpServletRequest;
/*
* @Author Alienworm
* @Description 将HttpServletRequest转换为JSONObject
* @Date 23:13 2019/12/18
* @Param [request]
* @return com.alibaba.fastjson.JSONObject
**/
public static JSONObject toJSONObject(HttpServletRequest request) {
httpServletRequest = request;
log.info("Get parameter url: " + request.getRequestURL());
JSONObject pathParameter = getParameterFromPath();
log.info("Path parameter: " + pathParameter.toJSONString());
JSONObject bodyParameter = getParameterFromBody();
log.info("Body parameter: " + bodyParameter.toJSONString());
return combineJSONObject(bodyParameter, pathParameter);
}
/*
* @Author Alienworm
* @Description 合并两个JSONObject
* @Date 23:13 2019/12/18
* @Param [jsonObject1, jsonObject2]
* @return com.alibaba.fastjson.JSONObject
**/
private static JSONObject combineJSONObject(JSONObject jsonObject1, JSONObject jsonObject2) {
for (String key : jsonObject2.keySet())
jsonObject1.put(key, jsonObject2.get(key));
return jsonObject1;
}
/*
* @Author Alienworm
* @Description 获取GET参数
* @Date 23:13 2019/12/18
* @Param []
* @return com.alibaba.fastjson.JSONObject
**/
private static JSONObject getParameterFromPath() {
Enumeration parameterNames = httpServletRequest.getParameterNames();
JSONObject pathParameter = new JSONObject();
while (parameterNames.hasMoreElements()) {
String parameterName = (String)parameterNames.nextElement();
Object parameter = httpServletRequest.getParameter(parameterName);
pathParameter.put(parameterName, parameter);
}
return pathParameter;
}
/*
* @Author Alienworm
* @Description 获取POST参数
* @Date 23:14 2019/12/18
* @Param []
* @return com.alibaba.fastjson.JSONObject
**/
private static JSONObject getParameterFromBody() {
JSONObject bodyParameter = new JSONObject();
try {
String bodyParameterString = "";
Stream stringStream = httpServletRequest.getReader().lines();
for (Object line : stringStream.toArray())
bodyParameterString += line.toString();
JSONObject tmp = JSONObject.parseObject(bodyParameterString);
bodyParameter = tmp != null ? tmp : bodyParameter;
} catch (Exception e) {
log.error(e.getMessage());
}
return bodyParameter;
}
}
Comments | NOTHING