【问题标题】:Flutter websocket with Spring-boot backend带有 Spring-boot 后端的 Flutter websocket
【发布时间】:2019-11-16 03:11:15
【问题描述】:

好的,Flutter 在食谱中有 WebSocket 配方 (here)。这对 websocket.org 测试服务器非常有效。

问题是我想连接我自己的 WebSocket 服务器。所以我首先使用了 SpringBoot 中的this tutorial

尝试从应用程序(我在这里使用模拟器)向 Spring Boot 后端发出请求无效。然后我开始修补并从 Spring Boot 后端删除 STOMP,并留下一个简单的 WebSocket 传递字符串。它在使用邮递员甚至网页时有效,但在应用程序中无效

当前状态在这个 GitHub 上(包括 spring boot 和 flutter 项目):https://github.com/Flavsditz/websocket_sandbox

这里有人有什么建议吗?

我很感激!

【问题讨论】:

    标签: spring-boot flutter websocket


    【解决方案1】:

    经过一番考虑,我发现了问题:

    问题是我的spring-boot服务器在localhost,但是flutter(也是android模拟器)有自己的环回服务。 所以在 Flutter 程序中调用 localhost 指的是另一个地方,而不是我想要的地方。

    我已将 localhost 替换为 ip 10.0.2.2,这是为帮助开发而设置的主机 PC 的别名。

    欲了解更多信息,请查看此答案:here

    当然,如果您想在真实设备上进行测试,则需要为外部发布后端,所以这个答案可能会更好:here

    【讨论】:

      【解决方案2】:

      flutter-websocket_test/lib/message_page.dart 中,第 6-7 行有以下内容:

        final WebSocketChannel channel = IOWebSocketChannel.connect(
          Uri(scheme: "ws", host: "locahost", port: 8080, path: "/socket"),
      

      您使用的是locahost 而不是localhost,因此请尝试更改它,看看它是否有效。

      【讨论】:

      • 感谢您指出这一点,但这确实只是我准备示例时的一个错字。
      【解决方案3】:

      感谢您的解决方案,如果您想在真实设备中进行测试,请补充说明,

      1. 真实设备和电脑都必须在同一个网络中。
        (在我的情况下,我使用从手机到电脑的热点)

      2. 使用 cmd 从电脑获取 IP,输入 ipconfig 获取 IP。
        (在我的情况下是IPv4 Address. . . . . . . . . . . : 192.168.43.423

      3. 现在粘贴您的 IP 而不是 localhost
        例如。

        IOWebSocketChannel.connect(Uri(scheme: "ws",host: "192.168.43.423",port: 8080,path: "/socket"))
        谢谢

      【讨论】:

        【解决方案4】:

        对于那些使用

        stomp_dart_client: ^0.3.7

        用sockjs,记得把token传给header

        initClient() async {
            try {
        
              if (_stompClient != null && _stompClient.connected) {
                return;
              }
        
              SharedPreferences _prefs = await SharedPreferences.getInstance();
              String token = _prefs.getString('access_token');
              User currentUser = User.fromPrefJson(jsonDecode(_prefs.get('current_user')));
              phone = currentUser.phone;
              if (token != null) {
                String requestUrl = '$baseUrl/websocket/tracker?access_token=$token'; // please note <<<<<
                StompClient stompClient = StompClient(
                    config: StompConfig.SockJS(
                        url: requestUrl,
                        stompConnectHeaders: {
                          'Authorization' : 'Bearer $token', // please note <<<<<
                        },
                        webSocketConnectHeaders: {
                          'Authorization' : 'Bearer $token', // please note <<<<<
                        },
                        onStompError: (StompFrame frame) {
                          print('A stomp error occurred in web socket connection :: ${frame.body}');
                        },
                        onWebSocketError: (dynamic frame) {
                          print('A Web socket error occurred in web socket connection :: ${frame.toString()}');
                        },
                        onDebugMessage: (dynamic frame) {
                          print('A debug error occurred in web socket connection :: ${frame.toString()}');
                        },
                        onConnect: (StompClient client, StompFrame connectFrame) {
                          print('${client.toString()} connected with the following frames ${connectFrame.body}');
                          _stompClient = client;
        
                          clientUnSubscribeFn = _stompClient.subscribe(
                              destination: '/topic/client',  headers: {},
                              callback: (frame) {
                                // Received a frame for this subscription
                                print(frame.body);
                                clientController.add(frame.body);
                              }
                          );
                        }
                    )
                );
                stompClient.activate();
              }
            } catch(e) {
              print('An error occurred ${e.toString()}');
            }
          }
        
        
          sendClientMessage(String msg) async {
              if (_stompClient != null && _stompClient.connected) {
              _stompClient.send(
                 destination: '/topic/client',
                 body: msg,
                headers: {}
             );
          }
          }

        别忘了更新 Spring 安全配置和 web socket 配置

        @Configuration
        public class WebsocketSecurityConfiguration extends AbstractSecurityWebSocketMessageBrokerConfigurer {
        
            @Override
            protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
                messages
                    .nullDestMatcher().authenticated()
                    .simpDestMatchers("/topic/tracker").hasAuthority(AuthoritiesConstants.ADMIN)
                   .simpSubscribeDestMatchers("/topic/**").authenticated()
                    .simpDestMatchers("/topic/**").authenticated()
                    // message types other than MESSAGE and SUBSCRIBE
                    .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
                    // catch all
                    .anyMessage().denyAll();
            }
        
            /**
             * Disables CSRF for Websockets.
             */
            @Override
            protected boolean sameOriginDisabled() {
                return true;
            }
        }
        
        
        // spring security configs for http
        
        @Override
            public void configure(HttpSecurity http) throws Exception {
                // @formatter:off
                http
                    .csrf()
                    .disable()
                    .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
                    .exceptionHandling()
                        .authenticationEntryPoint(problemSupport)
                        .accessDeniedHandler(problemSupport)
                .and()
                    .headers()
                    .contentSecurityPolicy("default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:")
                .and()
                    .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
                .and()
                    .featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
                .and()
                    .frameOptions()
                    .deny()
                .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                    .authorizeRequests()
                    .antMatchers("/api/**").authenticated()
                    .antMatchers("/websocket/tracker").hasAnyAuthority(
                        AuthoritiesConstants.ADMIN, AuthoritiesConstants.MANAGER, AuthoritiesConstants.STAFF,
                        AuthoritiesConstants.CLIENT, AuthoritiesConstants.DRIVER
                    )
                    .antMatchers("/websocket/**").permitAll()
                    .httpBasic()
                .and()
                    .apply(securityConfigurerAdapter());
                // @formatter:on
            }

        干杯

        【讨论】:

          猜你喜欢
          • 2021-04-04
          • 2021-01-16
          • 2018-09-25
          • 1970-01-01
          • 2021-05-15
          • 1970-01-01
          • 1970-01-01
          • 2018-04-18
          • 1970-01-01
          相关资源
          最近更新 更多