使用Spring MVC RequestMappingHandlerMapping和Spring Websocket的ServletWebSocketHandlerRegistry处理相同的URL


问题内容

我要拥有什么:

  • 客户发送GET / HTTP/1.1(无Connection: upgrade)-此请求应由RequestMappingHandlerMapping
  • 客户端Connection: upgrade与GET请求一起发送-此请求应由ServletWebSocketHandlerRegistry

我的Java配置:

@Configuration
@EnableWebSocket
public class WebsocketConfiguration extends WebMvcConfigurationSupport 
                                    implements WebSocketConfigurer {
    @Bean
    WebsocketComponent wsHandler() {
        return new WebsocketComponent();
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(wsHandler(), "/").setAllowedOrigins("*");
    }
}

我的webmvc控制器:

@Controller
public class Status {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String status() {
        return "OK";
    }
}

问题是-当MVC控制器优先时,它总是以HTTP 200响应,而WebSocket处理程序从未到达。当WebSocket处理程序具有优先权时-
它可以与WebSocket客户端一起使用,但是当我尝试使用HTTP客户端(浏览器)时,Can "Upgrade" only to "WebSocket". 它会以响应。是否可以用回退到我的MVC映射的方式替换此错误页面?还有其他配置可以使我首先描述吗?


问题答案:

问题是-当MVC控制器优先时,它总是以HTTP 200响应,WebSocket处理程序从未到达

RequestMappingHandlerMapping优先于时WebSocketHandlerMapping,对于它们都可以处理的对端点的请求(如果仅考虑URL),DispatcherServlet会将请求分派给@RequestMapping方法,而不是WebSocket处理程序。为了解决此问题,请限制@RequestMapping方法只提供不带Connection:Upgrade标头的请求:

@Controller
public class Status {
    @RequestMapping(value = "/", method = GET, headers = "Connection!=Upgrade")
    public String status() {
        return "OK";
    }
}

这样,当DispatcherServlet搜索该公共端点的处理程序时,它将考虑Connection:Upgrade标头的存在或不存在,以确定满足请求的正确处理程序。