关于java.lang.IllegalStateException: getWriter() has already been called for this response`的原理与解决

java.lang.IllegalStateException: getWriter() has already been called for this response

异常的原因是在 Spring MVC 中,如果在拦截器中直接调用 response.getWriter().write() 方法向客户端输出响应数据,就会导致这个异常。

下面的代码会出现这个错误:

public class LoginHandler implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        log.info("进入拦截器");
        if(request.getSession().getAttribute("employee") == null) {
            log.info("未登录");
            response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
            log.info("返回失败信息");
            return true;
        }
        return true;
    }
}

原理:

如果在拦截器中调用getwrite.write就直接会返回数据了,也就是做出了响应。如果拦截器最终放行,那么就会出现业务代码再次进行响应,从而出现两次响应,由于请求只接受一次响应,所以就会认为编写错误,从而会报错。

解决方法:

使用response.getOutputStream().write(),这里需要加上response.setContentType(“application/json;charset=utf-8”);
来保证返回的数据会被浏览器自动解析

public class LoginHandler implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=utf-8");
        log.info("进入拦截器");
        if(request.getSession().getAttribute("employee") == null) {
            log.info("未登录");
            response.getOutputStream().write(JSON.toJSONString(R.error("NOTLOGIN")).getBytes(StandardCharsets.UTF_8));
            log.info("返回失败信息");
            return true;
        }
        return true;
    }
}

为什么response.getOutputStream().write()不会报错

因为这个方法只是将响应数据写入了缓冲区内中,并没有发送到客户端,缓冲区会保留响应数据,直到这次请求最终结束,才将响应发到客户端,从而只产生一次响应

而response.getWriter().write()会直接将响应标记为已完成,因此后续的任何尝试都会抛出IllegalStateException

关于后端最终的返回数据

由于使用了response.getOutputStream().write() ,那么最终能返回的字节数据,而不是字符串,但是由于我们设置了response.setContentType(“application/json;charset=utf-8”);,浏览器会自动将其转换成json字符串。

我们不需要做任何处理,包括js中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值