Не удается правильно прочитать тело запроса в перехватчике - Spring BOOT 2.0.4 - PullRequest
0 голосов
/ 15 октября 2018

У меня проблема с чтением тела запроса в перехватчике.И getReader(), и getInputStream() вызывают проблемы.Мой перехватчик:

public class MyInterceptor extends HandlerInterceptorAdapter {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
        throws Exception {
    // TODO Auto-generated method stub

}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
        throws Exception {
    // TODO Auto-generated method stub
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    String requestBody = httpRequest.getReader().lines().collect(Collectors.joining(System.lineSeparator()));

//or
// String requestBody = new BufferedReader(new InputStreamReader(httpRequest.getInputStream()))
//                .lines().collect(Collectors.joining("\n"));
//some logic...
    return true;
}

Оба подхода терпят неудачу, потому что, вероятно, Spring использует такой ресурс где-то внутри.Первая причина java.lang.IllegalStateException: getReader () уже был вызван для этого запроса и других Отсутствует необходимое тело запроса: org.springframework.http.ResponseEntity ...

Я пробовал обходные пути с обертками без эффекта.Я думаю, потому что я не могу передать обертку, как в фильтрах (я не хочу использовать фильтр, потому что у меня есть общий менеджер исключений (@ControllerAdvice).

Это известная проблема? Есть ли обходной путь для этого?

1 Ответ

0 голосов
/ 23 октября 2018

Наконец, я понял это, поэтому я оставлю здесь несколько простых, но полезных советов для других.Я использовал оболочку запроса, но чтобы она работала должным образом, я добавил фильтр с наивысшим порядком, чтобы обернуть каждый запрос в оболочку в начале, до выполнения перехватчика.Теперь он работает хорошо;) Вот самый важный код - фильтр, чтобы обернуть каждый запрос в многопользовательскую оболочку (перехватчик выглядит почти так же, как и выше, и оболочка не изобретена мной, найдена в стеке, и я нашел ее наиболее понятной и читаемой):

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalWrapFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    MultiReadRequest wrapper = new MultiReadRequest((HttpServletRequest) request);
    chain.doFilter(wrapper, response);
}

@Override
public void destroy() {
}

class MultiReadRequest extends HttpServletRequestWrapper {

    private String requestBody;

    public MultiReadRequest(HttpServletRequest request) {
        super(request);
        try {
            requestBody = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody.getBytes());
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return byteArrayInputStream.available() == 0;
            }

            @Override
            public boolean isReady() {
                return true;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }

            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream(), Charset.forName("UTF-8")));
    }
}

}

...