SSE eventSource.cancel() 触发的处理逻辑

在客户端使用 OkHttp 框架EventSource 时,如果客户端调用 eventSource.cancel(),会触发 EventSourceListeneronClosed() 方法。同时,服务端会检测到客户端断开连接,并触发 SseEmitteronCompletion() 事件。


1. 客户端调用 eventSource.cancel() 的行为

客户端代码示例

import okhttp3.*;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;

public class SseClient {
    
    
    public static void main(String[] args) {
    
    
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url("http://localhost:8080/sse-stream")
                .build();

        EventSource.Factory factory = EventSources.createFactory(client);
        EventSource eventSource = factory.newEventSource(request, new EventSourceListener() {
    
    
            @Override
            public void onOpen(EventSource eventSource, Response response) {
    
    
                System.out.println("SSE connected!");
            }

            @Override
            public void onEvent(EventSource eventSource, String id, String type, String data) {
    
    
                System.out.println("Received event: " + data);
            }

            @Override
            public void onClosed(EventSource eventSource) {
    
    
                System.out.println("SSE closed by client.");
            }

            @Override
            public void onFailure(EventSource eventSource, Throwable t, Response response) {
    
    
                System.err.println("SSE error: " + t.getMessage());
            }
        });

        // 模拟客户端主动取消连接
        try {
    
    
            Thread.sleep(5000); // 等待 5 秒
            eventSource.cancel(); // 客户端主动取消连接
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }
}

客户端行为

  • 当调用 eventSource.cancel() 时:
    1. 客户端会主动关闭连接。
    2. 触发 EventSourceListeneronClosed() 方法。
    3. 不会触发 onFailure(),因为这是客户端主动取消的行为,而不是错误。

2. 服务端的响应

服务端代码示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@RestController
public class SseController {
    
    

    @GetMapping("/sse-stream")
    public SseEmitter streamEvents() {
    
    
        SseEmitter emitter = new SseEmitter();

        // 监听客户端断开连接
        emitter.onCompletion(() -> {
    
    
            System.out.println("Client disconnected: onCompletion");
        });

        // 监听连接超时
        emitter.onTimeout(() -> {
    
    
            System.out.println("Connection timeout: onTimeout");
        });

        // 模拟发送事件
        new Thread(() -> {
    
    
            try {
    
    
                for (int i = 0; i < 10; i++) {
    
    
                    emitter.send(SseEmitter.event().data("Event " + i));
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
    
    
                emitter.completeWithError(e);
            }
        }).start();

        return emitter;
    }
}

服务端行为

  • 当客户端调用 eventSource.cancel() 时:
    1. 服务端会检测到客户端断开连接。
    2. 触发 SseEmitteronCompletion() 事件。
    3. 如果设置了 onTimeout(),但客户端是主动断开连接,不会触发 onTimeout()

3. 执行流程

  1. 客户端
    • 连接成功后,接收事件。
    • 调用 eventSource.cancel(),触发 onClosed()
  2. 服务端
    • 检测到客户端断开连接,触发 onCompletion()

4. 总结

客户端行为 客户端回调方法 服务端回调方法
调用 eventSource.cancel() onClosed() onCompletion()
网络断开/超时 onFailure() onCompletion()onTimeout()
  • eventSource.cancel() 是客户端主动断开连接的行为,会触发 onClosed()
  • 服务端通过 onCompletion() 检测到客户端断开连接,并执行相应的清理逻辑。