@Override public BufferedReader getReader()throws IOException {
if (usingInputStream) { thrownewIllegalStateException(sm.getString("coyoteRequest.getReader.ise")); }
// InputBuffer has no easily accessible reference chain to the Context // to check for a default request character encoding at the Context. // Therefore, if a Context default should be used, it is set explicitly // here. Need to do this before setting usingReader. if (coyoteRequest.getCharacterEncoding() == null) { // Nothing currently set explicitly. // Check the content Contextcontext= getContext(); if (context != null) { Stringenc= context.getRequestCharacterEncoding(); if (enc != null) { // Explicitly set the context default so it is visible to // InputBuffer when creating the Reader. setCharacterEncoding(enc); } } }
코드를 보면 inputStream 이나 reader 는 두 번 읽어서 처리 할수 없게 되어 있습니다.
하지만 스프링의 유틸 클래스인 ContentCachingRequestWrapper 를 사용하면 처리 할수 있는 방법이 있습니다.
ContentCachingRequestWrapper는 입력 스트림 과 리더 에서 읽은 모든 내용을 캐시 하고 있습니다. 캐쉬된 내용은 getContentAsByteArray() 메소드를 사용해서 처리 할수 있습니다. 하지만 getInputStream 과 getReader를 두번 사용할 수 있는것은 아닙니다.
간단한 시나리오를 보면 filter를 통해서 request의 값을 읽어서 처리를 해야 될수도 있습니다.(예: 인증처리를 위해)
위의 코드에서 스프링의 @RequestBody를 사용하려고 하면 HttpMessageNotReadableException 이 발생한다. 왜냐 하면 getInputStream 과 getReader를 두번 사용할 수 없어서 이다.
ContentCachingRequestWrapper를 재사용 가능하게 바꾸는 논의도 있었는데 거절 당한 이력이 있다. 해당 클래스틑 유틸 클래스이고 이렇게 사용되는것이 ContentCachingRequestWrapper 클래스가 디자인된 방식이라서 수용이 안된다. 라는 답변이 달려 있다.
해결 방법은 간단하게 재사용 가능한 wrapper 클래스를 만들어서 사용하면 된다. 아래의 ReusableRequestWrapper 클래스를 만들어서 처리 하면 된다.