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

Spring中如何监听无@RestController及未映射请求?用于网关转发

嘿,你的需求其实很适合用Spring的过滤器(Filter)或者HandlerInterceptor来实现——比写一个通配符控制器优雅太多,而且能真正拦截所有到达服务的请求,包括那些没有对应@RequestMapping的请求。下面给你详细拆解几个可行的方案:

方案一:使用Servlet Filter(最推荐)

Servlet Filter是在DispatcherServlet之前执行的,属于Web容器层面的拦截器,不管请求有没有对应的Spring控制器映射,都会被拦截,完全符合你网关转发的需求。

实现步骤:

  1. 编写自定义Filter类,用@WebFilter指定拦截所有路径:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class RequestForwardFilter implements Filter {

    // 注入你用来查询下游映射的服务(从数据库取配置)
    // private DownstreamMappingService mappingService;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String requestUri = request.getRequestURI();
        
        // 1. 查询数据库,获取对应的下游URI
        // String downstreamUri = mappingService.getDownstreamUri(requestUri);
        
        // 2. 如果找到映射,就处理转发逻辑
        if (downstreamUri != null) {
            // 这里分两种情况:
            // - 下游是同容器内的服务:用RequestDispatcher转发
            // servletRequest.getRequestDispatcher(downstreamUri).forward(servletRequest, servletResponse);
            
            // - 下游是外部服务:用WebClient/RestTemplate发起请求并返回结果
            // String responseBody = WebClient.create()
            //         .method(request.getMethod())
            //         .uri(downstreamUri)
            //         .headers(headers -> headers.putAll(request.getHeaderNames().stream()
            //                 .collect(Collectors.toMap(h -> h, request::getHeader))))
            //         .bodyValue(request.getInputStream())
            //         .retrieve()
            //         .bodyToMono(String.class)
            //         .block();
            // servletResponse.getWriter().write(responseBody);
            
            return; // 处理完转发,直接结束流程,不走后续过滤器和Spring MVC
        }
        
        // 没有找到映射,继续走原流程(交给Spring MVC处理)
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
  1. 在Spring Boot启动类上添加@ServletComponentScan,让Spring扫描到你的Filter:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}
方案二:使用Spring MVC HandlerInterceptor

HandlerInterceptor属于Spring MVC层面的拦截器,在DispatcherServlet之后、具体Handler执行前触发。它能拦截所有进入Spring MVC的请求,适合只关注业务请求的场景。

实现步骤:

  1. 编写自定义Interceptor类:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class RequestForwardInterceptor implements HandlerInterceptor {

    // 注入映射服务
    // private DownstreamMappingService mappingService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestUri = request.getRequestURI();
        
        // 查询下游映射
        // String downstreamUri = mappingService.getDownstreamUri(requestUri);
        
        if (downstreamUri != null) {
            // 同样可以用WebClient调用外部服务并返回结果
            // 逻辑和Filter里的类似,这里不再重复
            return false; // 返回false,阻止后续Handler执行
        }
        
        // 没有映射,继续执行原流程
        return true;
    }
}
  1. 配置Interceptor使其生效:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private RequestForwardInterceptor requestForwardInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(requestForwardInterceptor)
                .addPathPatterns("/**"); // 拦截所有路径
    }
}
为什么不推荐你原来的通配符控制器?

用@RequestMapping("*")的方式有几个明显的问题:

  • 优先级问题:Spring MVC会优先匹配更具体的@RequestMapping,如果有其他控制器定义了更精确的路径,你的通配符控制器就不会被触发;
  • 范围有限:它只能拦截Spring MVC能识别的请求,比如静态资源、Actuator端点这类走特殊处理逻辑的请求,不会被这个控制器捕获;
  • 不够灵活:本质上是一个业务控制器,用来做网关转发逻辑会显得很牵强,后续扩展也不方便。
注意事项
  • 处理转发时,要注意请求头、请求体、请求方法的完整传递,不然下游服务可能无法正确处理请求;
  • 如果是转发到外部服务,推荐用WebClient(非阻塞)而不是RestTemplate(已过时);
  • 要做好异常处理,比如下游服务不可用时,返回合适的错误给客户端。

内容的提问来源于stack exchange,提问作者user3679686

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:09:54