ether-websocket-jetty12 integra los contratos de ether-websocket-core con Jetty 12, permitiendo registrar WebSocketEndpoint en el mismo servidor que los endpoints HTTP.
Instalación
<dependency>
<groupId>dev.rafex.ether.websocket.jetty12</groupId>
<artifactId>ether-websocket-jetty12</artifactId>
<version>8.0.0-SNAPSHOT</version>
</dependency>
Registrar WebSockets en un JettyModule
public class AppModule implements JettyModule {
private final AppContainer container;
@Override
public void configure(JettyModuleContext ctx) {
ctx.route(Route.of("/users", Set.of("GET", "POST")), new UsersResource(container));
ctx.websocket(WebSocketRoute.of("/chat/{room}", new ChatEndpoint()));
ctx.websocket(WebSocketRoute.of("/notifications", new NotificationsEndpoint(container)));
ctx.websocket(WebSocketRoute.of("/live/{stream}", new LiveDataEndpoint(container)));
}
}
Servidor con HTTP + WebSocket
JettyServerRunner runner = JettyServerFactory.create(serverConfig)
.module(new AppModule(container))
.build();
runner.start();
runner.await();
Autenticación en WebSocket (handshake HTTP)
Las conexiones WebSocket pasan primero por el pipeline HTTP. Usa el handler de auth para rechazar conexiones no autorizadas en la fase de upgrade:
public class AuthenticatedChatEndpoint implements WebSocketEndpoint {
private final TokenVerifier verifier;
public AuthenticatedChatEndpoint(TokenVerifier verifier) {
this.verifier = verifier;
}
@Override
public void onOpen(WebSocketSession session) {
String token = session.queryFirst("token");
var result = verifier.verify(token, Instant.now());
if (!result.isValid()) {
session.close(WebSocketCloseStatus.PROTOCOL_ERROR);
return;
}
session.attribute("userId", result.claims().subject());
LOG.info("WS autenticado: {}", result.claims().subject());
}
@Override
public void onText(WebSocketSession session, String message) {
String userId = (String) session.attribute("userId");
if (userId == null) return;
}
}
GlowrootWebSocketEndpointWrapper — APM para WebSockets
Si usas Glowroot, envuelve tus endpoints para visibilidad de transacciones:
ctx.websocket(WebSocketRoute.of("/chat/{room}",
new GlowrootWebSocketEndpointWrapper(new ChatEndpoint(), "chat")));
Más información