【问题标题】:HttpMessageNotReadableException: Could not read document: Stream closed;HttpMessageNotReadableException:无法读取文档:流已关闭;
【发布时间】:2017-08-23 12:39:14
【问题描述】:

我正在使用 Spring Boot 并使用过滤器过滤请求。 过滤器用于检查用户验证,该验证正在从请求正文中读取一些数据(为此我使用了 HttpServletRequestWrapper 实现)。从 requestWrapper 我得到了预期的数据,我的服务在过滤器中工作得很好。但是,当成功时,过滤器将请求传递给主控制器,我得到一个流关闭异常,如下所示:

   o.s.w.s.m.s.DefaultHandlerExceptionResolver - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Stream closed; nested exception is java.io.IOException: Stream closed

这是过滤器类:

@WebFilter(urlPatterns = {"/getDocs" })
public class AuthenticationFilter implements Filter{

    private static Logger logger = Logger.getLogger(AuthenticationFilter.class);

    @Autowired
    private UserVerificationService userVerificationService;

    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        logger.info("checking token in filter");
        HttpServletRequest request = (HttpServletRequest) arg0;
        DocVerificationRequestWrapper myRequestWrapper = new DocVerificationRequestWrapper((HttpServletRequest) request);
        String body = myRequestWrapper.getBody();
        Token token = null;
        try {
            JSONObject jsonObj = new JSONObject(body);
            JSONObject tokenObj = (JSONObject) jsonObj.get("token");
            Gson gson = new Gson();
            token = gson.fromJson(tokenObj.toString(), Token.class);

            if(null != token) {
                    if(userVerificationService==null){
                    ServletContext servletContext = request.getServletContext();
                    WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
                    userVerificationService = webApplicationContext.getBean(UserVerificationService.class);
                }
                    String verStatus = userVerificationService.verifyUser(token);
                    logger.info("verStatus = "+verStatus);
                    if(verStatus != null && verStatus.equalsIgnoreCase("success")) {
                        chain.doFilter(request, response);  
                    }else
                        logger.error("Invalid token");
            }else {
                    logger.error("token missing.");
            }
        } catch (JSONException e) {
                logger.error("exception in authetication filter " + e);
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub

    }

}

这里是 HttpServletRequestWrapper 实现类:

public class DocVerificationRequestWrapper extends HttpServletRequestWrapper {
 private final String body;
 public DocVerificationRequestWrapper(HttpServletRequest request) throws IOException {
   super(request);
   StringBuilder stringBuilder = new StringBuilder();
   BufferedReader bufferedReader = null;
   try {
     InputStream inputStream = request.getInputStream();
     if (inputStream != null) {
       bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
       char[] charBuffer = new char[128];
       int bytesRead = -1;
       while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
         stringBuilder.append(charBuffer, 0, bytesRead);
       }
     } else {
       stringBuilder.append("");
     }
   } catch (IOException ex) {
       throw ex;
   } finally {
     if (bufferedReader != null) {
       try {
         bufferedReader.close();
       } catch (IOException ex) {
         throw ex;
       }
     }
   }
   body = stringBuilder.toString();
 }

 @Override
 public ServletInputStream getInputStream() throws IOException {
   final ByteArrayInputStream byteArrayInputStream = new     ByteArrayInputStream(body.getBytes());
   ServletInputStream servletInputStream = new ServletInputStream() {
     public int read() throws IOException {
       return byteArrayInputStream.read();
     }

    @Override
    public boolean isFinished() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isReady() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void setReadListener(ReadListener listener) {
        // TODO Auto-generated method stub

    }
   };
   return servletInputStream;
 }

 @Override
 public BufferedReader getReader() throws IOException {
   return new BufferedReader(new InputStreamReader(this.getInputStream()));
 }

 public String getBody() {
   return this.body;
 }
}

任何建议,如何解决这个错误?

【问题讨论】:

    标签: java spring spring-boot httprequest spring-filter


    【解决方案1】:

    我猜那是因为您没有将实际的包装器传递给链,而是传递了原始请求。试试这个:

    if(verStatus != null && verStatus.equalsIgnoreCase("success")) {
        chain.doFilter(myRequestWrapper, response);  
    }
    

    显然,在 ObjectMapper 尝试读取请求正文时 - 请求输入流已经关闭,因为它已被您的包装器读取。

    【讨论】:

      猜你喜欢
      • 2013-06-10
      • 1970-01-01
      • 2017-03-20
      • 2013-08-17
      • 2020-05-19
      • 2012-11-10
      • 1970-01-01
      • 1970-01-01
      • 2011-01-20
      相关资源
      最近更新 更多