предисловие
Недавно я столкнулся с требованием в разработке, которое требует повторного чтенияHttpServletRequestЗапросите контент и установите пользовательские заголовки для передачи, но они появятсяRequired request body is missing, Причина вServletInputStreamПоток можно прочитать только один раз, тогда нам нужно только сделать так, чтобы содержимое запроса можно было прочитать повторно, доступ к которому можно получить черезHttpServletRequestWrapperреализовать.
Этапы реализации
1. НастроитьMutableHttpServletRequest
public class MutableHttpServletRequest extends HttpServletRequestWrapper {
private final String body;
private byte[] bytes;
private final Map<String, String> customHeaders;
public MutableHttpServletRequest(HttpServletRequest request) throws IOException {
super(request);
this.customHeaders = new HashMap<String, String>();
this.bytes = StreamUtils.copyToByteArray(request.getInputStream());
this.body = new String(this.bytes, StandardCharsets.UTF_8);
}
public void putHeader(String name, String value) {
this.customHeaders.put(name, value);
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (bytes == null) {
bytes = new byte[0];
}
final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
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() throws IOException {
return bais.read();
}
};
}
@Override
public String getHeader(String name) {
String headerValue = customHeaders.get(name);
if (headerValue != null) {
return headerValue;
}
return ((HttpServletRequest) getRequest()).getHeader(name);
}
@Override
public Enumeration<String> getHeaderNames() {
Set<String> set = new HashSet<String>(customHeaders.keySet());
@SuppressWarnings("unchecked")
Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
while (e.hasMoreElements()) {
String n = e.nextElement();
set.add(n);
}
return Collections.enumeration(set);
}
}
2. MutableHttpServletRequestиспользовать
-
Создайте
filterpublic class ReadRequestBodyFilter implements Filter { @Override public void init(FilterConfig filterConfiguration) throws ServletException { // do nothing } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException { request = new MutableHttpServletRequest((HttpServletRequest) request); // do nothing chain.doFilter(request, response); } @Override public void destroy() { // do nothing } } -
регистр
filtel@Bean public FilterRegistrationBean<BodyReaderFilter> Filters() { FilterRegistrationBean<ReadRequestBodyFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new ReadRequestBodyFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.setName("readRequestBody-filter"); registrationBean.setOrder(1); return registrationBean; }
Суммировать
httpСодержимое запроса можно прочитать только один раз, если вы читаете в фильтреbody, то цельservletне сможет его перечитать, что также вызываетIllegalStateException. используя приведенное вышеHttpServletRequestWrapper, вы можете прочитать тело HTTP-запроса, а затем сервлет сможет прочитать его позже. По сути, содержимое тела запроса кэшируется в объекте-оболочке, поэтому это может быть N раз на протяжении всего времени жизни запроса.
Справочная статья
Причина, по которой поток в httpServletRequest можно прочитать только один раз