WebSocketServerSockJsSession中的传输错误 - 无法在Spring Stomp websocket上加载平台配置程序

时间:2014-11-12 15:49:52

标签: angularjs spring-websocket

我正在尝试将网络套接字添加到我的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",

1 个答案:

答案 0 :(得分:2)

帮助在搜索“欢迎使用SockJS”时遇到此问题的其他人:如果您尝试使用常规websocket连接连接到SockJS地址,请将/ websocket添加到您网址的末尾。