Reputation: 462
How do I pass over the locale from http request to websocket in spring boot?
My locale is already set in LocaleContextHolder, but when I hand over to websocket, it's gone and it's default again. What's the right way to hand over the locale to websockets?
Upvotes: 1
Views: 1089
Reputation: 462
Ok, I found a solution. Since LocaleContextHolder is thread based and websockets are running asynchronously, things get lost from the request. But luckily there is HandshakeInterceptor to hand over certain things to websocket sessions.
My config:
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketBrokerConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<Session> {
// ...
@Override
protected void configureStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*")
.addInterceptors(new HttpWebsocketHandshakeInterceptor()) // <-- The interceptor
.withSockJS();
}
// ...
}
The interceptor:
public class HttpWebsocketHandshakeInterceptor implements HandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
Locale locale = LocaleContextHolder.getLocale();
attributes.put(WSConstants.HEADER_HTTP_LOCALE, locale);
// hand over more stuff, if needed ...
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
Exception exception) {
}
}
WSConstants.HEADER_HTTP_LOCALE
is just a string constant. Call it whatever you like.
Then in your controller:
@Controller
public class WSController {
@MessageMapping("/somewhere/")
public void message(
SimpMessageHeaderAccessor headerAccessor,
Principal principal,
WSMessage frame) {
// update locale to keep it up to date
Map<String, Object> sessionHeaders = headerAccessor.getSessionAttributes();
Locale locale = (Locale) sessionHeaders.get(WSConstants.HEADER_HTTP_LOCALE);
if (locale != null) {
LocaleContextHolder.setLocale(locale);
}
// use your localized stuff as you used to
}
@SubscribeMapping("/somewhereelse/")
public ChannelPayload bubble(
SimpMessageHeaderAccessor headerAccessor,
Principal principal
) {
// update locale to keep it up to date
Map<String, Object> sessionHeaders = headerAccessor.getSessionAttributes();
Locale locale = (Locale) sessionHeaders.get(WSConstants.HEADER_HTTP_LOCALE);
if (locale != null) {
LocaleContextHolder.setLocale(locale);
}
// use your localized stuff as you used to
return null;
}
}
Hope this helps others with the same issues.
Upvotes: 1