You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android+Spring Boot聊天应用中WebSocket onMessage方法未触发求助

问题:Android OkHttp WebSocket无法接收Spring Boot后端返回的STOMP消息

前端(Android OkHttp)代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button connectBtn=findViewById(R.id.connectBtn);
        connectBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder().url("ws://localhost:8080/ws").build();
                WebSocketListener listener=new WebSocketListener() {
                    @Override
                    public void onClosed(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
                        super.onClosed(webSocket, code, reason);
                        output("Closed: "+reason);
                    }

                    @Override
                    public void onClosing(@NonNull WebSocket webSocket, int code, @NonNull String reason) {
                        super.onClosing(webSocket, code, reason);
                        output("Closing: "+reason);
                    }

                    @Override
                    public void onFailure(@NonNull WebSocket webSocket, @NonNull Throwable t, @Nullable Response response) {
                        super.onFailure(webSocket, t, response);
                        output("Failed: "+ t);
                    }

                    @Override
                    public void onMessage(@NonNull WebSocket webSocket, @NonNull String text) {
                        super.onMessage(webSocket, text);
                        output("Received: "+text);
                    }

                    @Override
                    public void onMessage(@NonNull WebSocket webSocket, @NonNull ByteString bytes) {
                        super.onMessage(webSocket, bytes);
                        output("Received bytes: "+bytes.hex());
                    }

                    @Override
                    public void onOpen(@NonNull WebSocket webSocket, @NonNull Response response) {
                        super.onOpen(webSocket, response);
                        Message message=new Message("Hello");
                        Gson gson=new Gson();
                        String jsonMessage=gson.toJson(message);
                        output("connected: "+response);
                        webSocket.send("SUBSCRIBE\n" +
                                "destination:/topic/public\n" +
                                "id:sub-01\n" +
                                "\n" +
                                "\0");

                        webSocket.send("SEND\n" +
                                "destination:/app/message\n" +
                                "Content-Type: application/json\n"+
                                "\n" +
                                jsonMessage +
                                "\0");
                    }
                };
                WebSocket webSocket= client.newWebSocket(request,listener);
            }
        });
    }
    public void output(String s){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(s);
            }
        });
    }
}

后端(Spring Boot)代码

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws");
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app");
        registry.enableSimpleBroker("/topic");
    }
}
@Controller
public class ChatController {
    @MessageMapping("/message")
    @SendTo("/topic/public")
    public Message sendMessage(Message message){
        System.out.println(message);
        return message;
    }
}

问题描述

使用Android(OkHttp)和Spring Boot开发聊天应用,已成功建立WebSocket连接,消息"Hello"可正常发送至后端并打印;后端sendMessage方法已返回Message对象,但WebSocket监听器的onMessage方法始终未被调用。


解决方案

1. 核心问题:STOMP协议与原生WebSocket的差异

你用Spring Boot配置的是STOMP协议(基于WebSocket的上层应用协议),但OkHttp的WebSocket只是底层的字节流传输工具,不会自动解析STOMP的帧格式。后端返回的是完整的STOMP消息帧,而非单纯的JSON数据,你的前端代码没有正确处理这种格式,导致看似没收到消息(实际可能收到了但没识别)。

2. 先确认是否真的收到消息

修改onMessage方法,完整打印收到的原始文本:

@Override
public void onMessage(@NonNull WebSocket webSocket, @NonNull String text) {
    super.onMessage(webSocket, text);
    // 完整打印所有收到的内容,包括STOMP帧的头部和分隔符
    output("Raw received content:\n" + text);
}

如果收到类似以下内容,说明消息已到达,只是需要解析:

MESSAGE
destination:/topic/public
content-type:application/json
content-length:13

{"content":"Hello"}
\0

3. 两种处理方式

方式一:使用STOMP客户端库(推荐)

直接用现成的STOMP客户端库处理协议解析,避免手动处理帧格式。比如stomp-android:

  • 添加Gradle依赖:
    implementation 'com.github.NaikSoftware:StompProtocolAndroid:2.0.7'
    
  • 示例代码:
    StompClient stompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, "ws://localhost:8080/ws");
    
    // 订阅主题
    stompClient.topic("/topic/public").subscribe(topicMessage -> {
        // 直接拿到解析后的JSON body
        String jsonBody = topicMessage.getPayload();
        Message message = new Gson().fromJson(jsonBody, Message.class);
        output("Received message: " + message.getContent());
    });
    
    // 连接并发送消息
    stompClient.connect();
    stompClient.send("/app/message", new Gson().toJson(new Message("Hello"))).subscribe();
    

方式二:手动解析STOMP帧(不推荐)

如果坚持用OkHttp原生处理,需要自己拆分STOMP帧的结构:
STOMP帧格式为:COMMAND\nHEADERS\n\nBODY\0
可以按以下步骤解析:

@Override
public void onMessage(@NonNull WebSocket webSocket, @NonNull String text) {
    super.onMessage(webSocket, text);
    // 去掉末尾的\0分隔符
    String frame = text.replace("\0", "");
    // 分割帧的各个部分
    String[] parts = frame.split("\n\n", 2);
    if (parts.length == 2) {
        // parts[0]是COMMAND和HEADERS,parts[1]是BODY(即后端返回的JSON)
        String jsonBody = parts[1].trim();
        Message message = new Gson().fromJson(jsonBody, Message.class);
        output("Received parsed message: " + message.getContent());
    }
}

4. 额外注意点

  • 确保Android设备能访问后端的ws://localhost:8080/ws:如果是模拟器,localhost对应模拟器的10.0.2.2,所以URL要改成ws://10.0.2.2:8080/ws。
  • 检查后端是否正确配置了跨域:如果Android应用和后端不在同一域,需要在WebSocketConfig中添加跨域支持:
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOriginPatterns("*");
    }
    

内容的提问来源于stack exchange,提问作者Awsaf Tasusif 2132066642

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 02:47:03