You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:52:44