最近springmvc项目升级成springboot,发现以前已经接入的一个系统向重构后的项目发送请求时,项目无法从HttpRequest中获取报文体。在springmvc项目中通过request.getInputStream();
方式获取报文体,在springboot中得到inputstream是null,用@RequestBody注解也同样获取不到报文。用request.getParameterMap()
确能获取到key是<?xmlversion=
,value是"1.0" encoding="UTF-8" ?>...
的表单,说明项目将报文按照表单的格式进行了分隔。
使用抓包软件对发送过来的报文抓包进行分析之后发现,发来的http请求报文头里面设置了Content-type 为x-www-form-urlencoded,然而我们需要解析的是xml报文。
抓包的报文头部分 经排查是一个HiddenHttpMethodFilter的过滤器去获取了parameterMap,如下图所示: HiddenHttpMethodFilter
解决方案:
1、 禁用这个filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new HiddenHttpMethodFilter();
}
@Bean
public FilterRegistrationBean disableSpringBootHiddenHttpMethodFilter(HiddenHttpMethodFilter filter) {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(filter);
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
2、重写这个filter
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter(){
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
}
};
}
一般按照以上两种方式就可以获取xml报文了,但是我发现使用了我们公司的日志框架之后,还是获取不到xml报文,看了我司的自动打印收发日志的框架之后发现了如下的代码:
InputStreamWrapper
都是先获取表单,再获取报文体,于是需要自己加一个过滤器,针对这个路径先获取报文体,创建自己的过滤器,并且注册到FilterRegistrationBean
,代码如下:
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean requestBodyFilter() {
FilterRegistrationBean filterRegistrationBean = new
FilterRegistrationBean(new RequestBodyFilter());
filterRegistrationBean.setDispatcherTypes(REQUEST);
filterRegistrationBean.setName("inputStreamReplaceServletFilter");
// filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 5);
filterRegistrationBean.addUrlPatterns("/oc/charge");
filterRegistrationBean.addUrlPatterns("/oc/query");
return filterRegistrationBean;
}
class InputStreamReplacementHttpRequestWrapper extends HttpServletRequestWrapper {
private String requestBody;
private Map<String, String[]> parameterMap;
public InputStreamReplacementHttpRequestWrapper(HttpServletRequest request)
throws IOException {
super(request);
requestBody = StreamUtils.copyToString(request.getInputStream(), Constant.DEFAULT_CHARSET);
parameterMap = new HashMap<String,String[]>(request.getParameterMap());
parameterMap.put("ocxmldata", new String[] {requestBody});
}
public String getRequestBody() {
return requestBody;
}
@Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream is = new ByteArrayInputStream(
requestBody.getBytes(Constant.DEFAULT_CHARSET_NAME));
return new ServletInputStream() {
@Override
public int read() throws IOException {
return is.read();
}
@Override
public boolean isFinished() {
return is.available() <= 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public String getParameter(String name) {
String[] values = parameterMap.get(name);
if (values != null) {
if(values.length == 0) {
return "";
}
return values[0];
} else {
return null;
}
}
@Override
public Map<String, String[]> getParameterMap() {
return parameterMap;
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameterMap.keySet());
}
@Override
public String[] getParameterValues(String name) {
return parameterMap.get(name);
}
}
class RequestBodyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
// System.out.println("init RequestBodyFilter");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
// System.out.println("doFilter RequestBodyFilter");
HttpServletRequest req = (HttpServletRequest) request;
request = new InputStreamReplacementHttpRequestWrapper(req);
chain.doFilter(request, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
}
网友评论