SpringBoot 调用错:getWriter() has already been called for this response

这篇具有很好参考价值的文章主要介绍了SpringBoot 调用错:getWriter() has already been called for this response。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这个错误通常表明您尝试从Spring MVC返回一个已使用的HttpServletResponse对象。

原因:这可能是由于直接调用HttpServletResponsegetWriter()getOutputStream()方法,或者由于在控制器方法中抛出异常而自动调用HttpServletResponsewrite()方法。

修改建议:您可以确保在控制器方法中没有调用任何HttpServletResponse的方法,并且不要在控制器方法中抛出异常。

规避建议:如果需要向客户端返回响应,请使用返回相应的对象,例如StringModelAndViewRedirectView。 此外,您还可以使用@ResponseStatus@ExceptionHandler注解来处理异常情况,并生成适当的响应。文章来源地址https://www.toymoban.com/news/detail-794860.html

问题重现

ResponsePostInterceptor 里注入response.getWriter().write

package com.zhangziwa.practisesvr.interceptor;

import com.zhangziwa.practisesvr.utils.response.ResponseContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Component
public class ResponsePostInterceptor implements HandlerInterceptor {

	# 调用 response.getWriter().write
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.err.println("***ResponsePostInterceptor.preHandle***");
        response.setHeader("test-test", "test-test");
        response.getWriter().write("Response content");
        response.flushBuffer();
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.err.println("***ResponsePostInterceptor.postHandle***");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.err.println("***ResponsePostInterceptor.afterCompletion***");
        ResponseContext.clear();
    }
}

Controller 正常返回 ResponseEntity

    @RequestMapping(value = "/getAllStudents4", method = RequestMethod.GET)
    public ResponseEntity<List<Student>> getAllStudents4() {
        System.err.println("***Controller.getAllStudents4***");

        List<Student> students = userService.listStudents3(1, 5);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("test", "test");
        return ResponseEntity.ok().headers(httpHeaders).contentType(MediaType.APPLICATION_JSON).body(students);
    }

ResponseBodyAdvice 对 ResponseEntity进行增强

import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import static java.util.Objects.nonNull;

@ControllerAdvice
public class ResponsePostAdvice implements ResponseBodyAdvice {


    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        System.err.println("***ResponsePostAdvice.supports***");
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class clazz, ServerHttpRequest request, ServerHttpResponse response) {
        System.err.println("***ResponsePostAdvice.beforeBodyWrite***");
        HttpHeaders headers = response.getHeaders();

        // 分页信息添加到ServerHttpResponse
        HttpHeaders headersContext = ResponseContext.getHeaders();

        if (nonNull(headersContext) && !headersContext.isEmpty()) {
            headersContext.forEach((key, values) -> values.forEach((value) -> {
                headers.addIfAbsent(key, value);
            }));
        }

        // 状态码添加到ServerHttpResponse
        if (nonNull(ResponseContext.getResponseCode())) {
            response.setStatusCode(ResponseContext.getResponseCode());
        }
        
        # 这里会报错
        return body;
    }
}

异常拦截GlobalExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseEntity<String> handleException(Exception ex) {
        System.err.println("***GlobalExceptionHandler.handleException:" + ex.getMessage() + "***");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred");
    }

    @ExceptionHandler(NotFoundException.class)
    public ResponseEntity<String> handleNotFoundException(NotFoundException ex) {
        System.err.println("***GlobalExceptionHandler.handleNotFoundException***");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
    }
}

调用路径分析

# 拦截器的preHandle (这里注入了response.getWriter().write)
***ResponsePostInterceptor.preHandle***
# Controller层
***Controller.getAllStudents4***

# ResponsePostAdvice进行增强后返回ServerHttpResponse
***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***
## 这里报IllegalStateException了 被 @ControllerAdvice修饰的GlobalExceptionHandler 拦截到
***GlobalExceptionHandler.handleException:getWriter() has already been called for this response***

# 异常返回ResponseEntity 又被ResponsePostAdvice捕捉然后进行增强
***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***
# 又报IllegalStateException,但是此时没被GlobalExceptionHandler 拦截
java.lang.IllegalStateException: getWriter() has already been called for this response
# 吃啥程序蹦了,故ResponsePostInterceptor.postHandle未执行。但是afterCompletion是否异常都会执行,所以执行了
***ResponsePostInterceptor.afterCompletion***

# 这里又执行一遍拦截器,但是未进入Controller层,不是很懂
***ResponsePostInterceptor.preHandle***
***ResponsePostInterceptor.postHandle***
***ResponsePostInterceptor.afterCompletion***

到了这里,关于SpringBoot 调用错:getWriter() has already been called for this response的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Cannot Reference “XxxClass.xxxmember” Before Supertype Constructor Has Been Called

    百度翻译:在调用超类型构造函数之前无法引用“XxxClass.xxx” ----- 我的理解:在一个类的构造器方法还未执行的时候,我们无法使用这个类的成员属性或成员方法。   下面是会出现此错误的示例代码 IDE提示错误: Cannot reference \\\'MyException.getErrorCode\\\' before supertype constructor has

    2024年02月09日
    浏览(36)
  • 报错解决:Cannot call sendError() after the response has been committed

    报错背景:   在做开源项目《瑞吉外卖》时,编写拦截器代码后,前端登录时,后端报错如下:            思考与思路:          Cannot call sendError() after the response has been committed.....意思是,当response已经提交后,不能再sendError()。那也就是说,我在代码中一定是

    2024年02月11日
    浏览(43)
  • IDEA之This license XXXX has been suspended

    IDEA激活码突然报如下错误: 解决方案: IDEA版本2022.2.3,亲测管用

    2024年04月10日
    浏览(47)
  • 解决:Springboot启动报错 Whitelabel Error Page: This application has no explicit mapping for

    目录 解决:Spring Boot启动报错 Whitelabel Error Page: This application has no explicit mapping for 问题背景 解决步骤 第一步:检查代码 第二步:检查Spring Boot配置 第三步:检查Controller层 第四步:检查依赖项 第五步:重启应用 总结 @RequestMapping @GetMapping @PostMapping 当我们使用Spring Boot框架开

    2024年02月03日
    浏览(65)
  • 解决java.lang.IllegalStateException: Cannot call sendError() after the response has been committed异常

    相信大家自己在用spring boot写restful风格的接口时特别是写文件下载或文件导出时会碰到java.lang.IllegalStateException: Cannot call sendError() after the response has been committed这样的bug,很多人可能一脸困惑,就好奇为什么我文件都已经可以正常导出了,为什么在日志中还是会出现这样的报错

    2024年02月16日
    浏览(44)
  • 解决 This request has been blocked; this endpoint must be available over WSS.

    使用WebSocket在本地是没有问题的,能够和前端进行正常交互,但是将项目部署到服务器上,发现和前端建立不了WebSocket的连接,打开浏览器控制台报错: This request has been blocked; this endpoint must be available over WSS. 1、 首先我们要明白 wss协议实际是websocket+SSL,就是在websocket协议上

    2023年04月09日
    浏览(40)
  • java.lang.IllegalStateException: Illegal access: this web application instance has been stopped

    java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already.  Could not load [org.apache.logging.log4j.core.impl.Log4jLogEvent$Builder]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access. 部署web项目出现在这个问题,其

    2024年02月16日
    浏览(38)
  • 【报错】:Module path has been externalized for browser...

    Vite2+Vue3下引入path模块报错:Module “path” has been externalized for brower compatibility and cannot be accesed in client code 原因是 vite 源码中设定了不允许在客户端代码中访问内置模块代码。 1,安装 npm install path-browserify 2,使用 path-browserify 代替 path 模块 3,不再使用 import path from \\\'path\\\' ,改

    2024年02月12日
    浏览(53)
  • Unity寻路报错“SetDestination“ can only be called on an active agent that has been placed on a NavMesh.

    这个报错表示NavMeshAgent所在节点未放置在寻路网格上。出现这个错误一般伴有 \\\"Failed to create agent because it is not close enough to the NavMesh\\\"类似警告。 表明寻路代理创建失败,后续设置目的地肯定就会导致失败。 出现此类问题需要检查: 在调用SetDestination的时候,NavMeshAgent是否启用

    2023年04月08日
    浏览(44)
  • 【WEB前端】【报错解决】This request has been blocked; the content must be served over HTTPS....

    部署WEB项目后,开启了强制HTTPS,产生如下错误: 报错的原因就是当前页面是https协议加载的,但是这个页面发起了一个http的ajax请求,这种做法是非法的。HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的.在HTTPS页面里通过AJAX的方式请求HTTP资源,也会被

    2024年02月13日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包