我有一个正在运行的 Spring 多租户应用程序。它使用熟悉的线程局部变量和 Web 过滤器结构,并使用主机名(子域)来确定哪个租户处于活动状态。
但是浏览器也会打开一个 websocket 并发送消息。不知何故,我需要在那里做同样的事情;我需要将传入消息与租户(也称为用于启动 Websocket 的主机名)进行匹配。没有 Websocket 过滤器的概念。
有一个 HandshakeInterceptor,可以在其中访问主机名,或者可以通过 WebSocketEventListener 访问,因此可能可以在那里构造一些东西。但我似乎找不到一种方法将传入消息(在 @Controller 类的 @MessageMapping 方法中)链接到任何合理的东西。
关于如何做到这一点有什么见解吗?
这需要一些挖掘,但对于最终提出同样问题的人来说。将从 HttpServletRequest 确定租户 ID 的代码以及配置和日志记录(例如 MDC)的代码放在可重用静态方法中的 de TenantFilter 中。然后:
.addInterceptors(new HandshakeInterceptor() {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
// Determine the tenantId (see TenantFilter)
ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) request;
HttpServletRequest httpServletRequest = servletServerHttpRequest.getServletRequest();
String tenantId = TenantFilter.determineTenantId(httpServletRequest, ...);
attributes.put("tenantId", tenantId);
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
}
})
@MessageMapping("/SetNoteworthy")
public void browserToBackend(SetNoteworthy command, @Header("simpSessionId") String sessionId, @Header("simpSessionAttributes") Map<String, String> attributes) throws Exception {
String tenantId = attributes.get("tenantId");
if (LOG.isInfoEnabled()) LOG.info(BROWSER_TO_BACKEND + command);
TenantFilter.setCurrentTenant(tenantId, ...);
}