我正在尝试将网络套接字添加到我的AngularJS应用程序中。
我使用服务器上的Spring 4和客户端上的Stomp SockJS设置Web套接字。
我在http://localhost:9000/#/project/1/bts
命令后访问grunt serve
页面。
但是在进行Web套接字握手时我收到了500响应:
WebSocket connection to 'ws://localhost:8080/nitro-project-rest/api/socket/bts/405/bmtcztq4/websocket' failed: Error during WebSocket handshake: Unexpected response code: 500
服务器可以对每个失败的websocket请求说明:
SEVERE: Servlet.service() for servlet [NITRo] in context with path [/nitro-project-rest] threw exception [Request processing failed; nested exception is org.springframework.web.socket.sockjs.SockJsException: Uncaught failure in SockJS request, uri=http://localhost:8080/nitro-project-rest/api/socket/bts/970/2xoe6kls/websocket; nested exception is org.springframework.web.socket.sockjs.SockJsTransportFailureException: WebSocket handshake failure; nested exception is java.lang.RuntimeException: Cannot load platform configurator] with root cause
java.lang.RuntimeException: Cannot load platform configurator
有关错误的更多信息:
2017-02-06 10:36:04,241 DEBUG [http-bio-8080-exec-10] o.s.w.s.h.LoggingWebSocketHandlerDecorator Transport error in WebSocketServerSockJsSession[id=nqj286ob]
java.lang.RuntimeException: Cannot load platform configurator
at javax.websocket.server.ServerEndpointConfig$Configurator.fetchContainerDefaultConfigurator(ServerEndpointConfig.java:123)
at javax.websocket.server.ServerEndpointConfig$Configurator.getContainerDefaultConfigurator(ServerEndpointConfig.java:128)
at javax.websocket.server.ServerEndpointConfig$Configurator.checkOrigin(ServerEndpointConfig.java:192)
有趣的是推送通知正常。当预期的事件发生时,我可以看到网页正在更新。所以我的websocket工作正常,尽管有这个例外。页面加载时会发生此异常。
当我手动输入网址时:
http://localhost:8080/nitro-project-rest/api/socket/bts
在Chromium网页浏览器中显示:欢迎使用SockJS!
这是我的网络套接字连接服务:
function StompService(endpoint) {
this.stompClient = Stomp.client(ENV.NITRO_PROJECT_WS_URL + '/socket/' + endpoint);
}
StompService.prototype.connect = function(onConnect, onError) {
this.stompClient.connect({}, function(frame) {
$rootScope.$apply(function() {
onConnect.apply(stompClient, frame);
});
}, function(frame) {
$rootScope.$apply(function() {
onError.apply(stompClient, frame);
});
}, '/');
};
控制器:
var stomp = new SocketService(BTS_WS_ENDPOINT);
stomp.connect(function() {
$scope.client.subscribe('status', function(message) {
$scope.messages.push(message.body);
});
}, function() {
});
使用服务器端配置和控制器:
@Configuration
@EnableWebSocketMessageBroker
@ComponentScan(basePackages = "com.nsn.nitro.project.rest.socket")
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// Prefix for destinations towards the server
config.setApplicationDestinationPrefixes("/app");
// Prefix for destinations towards the client
config.enableSimpleBroker("/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// All controllers need to be added to the endpoint registry
registry.addEndpoint("/socket/bts").withSockJS();
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
}
@Override
public void configureClientOutboundChannel(ChannelRegistration registration) {
registration.taskExecutor().corePoolSize(4).maxPoolSize(10);
}
}
@Controller
public class BTSSocketController {
private static Logger logger = LoggerFactory.getLogger(BTSSocketController.class);
@MessageMapping("/socket/bts")
@SendTo("/topic/status")
public BTSMessage status(BTSMessage message) throws Exception {
logger.debug("==========>> Received the message " + message.getBtsId());
message.setStatus(BTSStatus.ONAIR);
return message;
}
}
我正在运行带有基本身份验证的Spring Security和以下配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(simpleCORSFilter, ChannelProcessingFilter.class);
http
.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic().authenticationEntryPoint(restAuthenticationEntryPoint)
.and().authorizeRequests().antMatchers("/socket/**").permitAll()
.and().authorizeRequests().antMatchers("/resources/**").permitAll()
.and().authorizeRequests().antMatchers(RESTConstants.SLASH + RESTConstants.ADMINS + RESTConstants.SLASH + RESTConstants.LOGIN).permitAll()
.and().authorizeRequests().antMatchers("/**").hasRole("ADMIN").anyRequest().authenticated();
}
@Component
public class SimpleCORSFilter implements Filter {
private static final String ORIGIN = "Origin";
private static final String OPTIONS = "OPTIONS";
private static final String OK = "OK";
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
if (httpServletRequest.getHeader(ORIGIN) != null) {
String origin = httpServletRequest.getHeader(ORIGIN);
httpServletResponse.setHeader("Access-Control-Allow-Origin", origin);
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "Accept-Language,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization,X-Filename,Content-Disposition,Content-Length");
// Allow more than the 6 default headers to be returned, as the content length is required for a download file request to get the file size
httpServletResponse.setHeader("Access-Control-Expose-Headers", "Accept-Language,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization,X-Filename,Content-Disposition,Content-Length");
}
if (httpServletRequest.getMethod().equals(OPTIONS)) {
try {
httpServletResponse.getWriter().print(OK);
httpServletResponse.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
我的Java依赖项是:
[INFO] +- javax.websocket:javax.websocket-api:jar:1.1:provided
[INFO] +- org.springframework:spring-web:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-test:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-messaging:jar:4.3.6.RELEASE:compile
[INFO] +- org.springframework:spring-websocket:jar:4.3.6.RELEASE:compile
我的Js依赖是:
"sockjs": "~0.3.4",
"stomp-websocket": "~2.3.4",
答案 0 :(得分:2)
帮助在搜索“欢迎使用SockJS”时遇到此问题的其他人:如果您尝试使用常规websocket连接连接到SockJS地址,请将/ websocket添加到您网址的末尾。