如何在Nginx+AngularJS+SpringBoot环境下禁止打印错误堆栈信息
解决方案
1. 禁止"Host does not match SNI"错误返回堆栈信息
该错误属于TLS握手阶段的校验错误,发生在SpringBoot全局异常处理器生效之前,需分场景处理:
场景A:Nginx作为SSL终止层(推荐方案)
若Nginx负责处理SSL握手,直接在Nginx层拦截并替换错误响应,避免请求到达后端:
在Nginx的SSL server块中添加以下配置:
server { listen 443 ssl; server_name your-domain.com; # 你的SSL证书配置 ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; # 自定义400错误响应,屏蔽原始错误和堆栈 error_page 400 @bad_request; location @bad_request { add_header Content-Type application/json; return 400 '{"code":400,"message":"Invalid Request"}'; } # 代理到后端SpringBoot的配置 location / { proxy_pass http://your-backend-ip:port; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
所有400错误都会返回定义的简洁响应,不会暴露任何堆栈信息。
场景B:SpringBoot直接处理SSL(内嵌服务器)
若SpringBoot直接处理SSL连接,需配置内嵌服务器的错误处理逻辑:
若使用Jetty作为内嵌服务器
创建Jetty自定义配置类,覆盖错误处理:
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ErrorHandler; import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Configuration public class JettyErrorConfig { @Bean public JettyServerCustomizer jettyErrorHandler() { return server -> { ErrorHandler customErrorHandler = new ErrorHandler() { @Override protected void handleErrorPage(org.eclipse.jetty.server.Request request, HttpServletResponse response, int code, String message) throws IOException { // 匹配目标错误,返回自定义响应 if (code == 400 && "Host does not match SNI".equals(message)) { response.setStatus(400); response.setContentType("application/json"); response.getWriter().write("{\"code\":400,\"message\":\"Invalid Request\"}"); } else { super.handleErrorPage(request, response, code, message); } } }; // 全局关闭堆栈显示 customErrorHandler.setShowStacks(false); server.setErrorHandler(customErrorHandler); }; } }
同时在配置文件中关闭默认错误的堆栈输出:
# application.properties server.error.include-stacktrace=never server.error.include-message=never
若使用Tomcat作为内嵌服务器
创建Tomcat配置类指定自定义错误页:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.ErrorPage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; @Configuration public class TomcatErrorConfig { @Bean public TomcatServletWebServerFactory tomcatFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400")); return factory; } }
再创建一个处理错误请求的Controller:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/error") public class CustomErrorController { @GetMapping("/400") public String handleBadRequest() { return "{\"code\":400,\"message\":\"Invalid Request\"}"; } }
2. 为何返回信息涉及Jetty?
SpringBoot默认内嵌Tomcat服务器,但如果项目存在以下情况,会自动切换为Jetty:
- 显式引入
spring-boot-starter-jetty依赖,并排除spring-boot-starter-tomcat - 项目间接依赖中包含Jetty,且优先级高于Tomcat
检查你的依赖管理文件:
Maven(pom.xml)
若存在类似配置,说明使用Jetty:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
Gradle(build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jetty' configurations { all { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } }
此时TLS握手阶段的SNI校验由Jetty处理,所以错误堆栈会包含Jetty的相关代码。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

