不写前端代码,curl直接调试sse

不写前端代码,curl直接开两个终端调试sse

过程:

客户端向服务端发送建立连接请求;
服务端向客户端推送内容;
服务端向客户端发送结束信号并结束

注意事项:

只有连接时要求content-type是xxx

其他问题:

服务端打算断开时,是否需要先得到客户端应答再断开?

java代码参考:

controller层


@RestController
public class ChatController {

    @Autowired
    private ChatService chatService;

    // TODO: 2023/10/16 执行顺序
    @CrossOrigin
    @PostMapping(value = "/ask")
    @SneakyThrows
    public void chatGPT(@RequestBody ChatRequest request) {
        chatService.chat(request);// TODO: 2023/10/16 执行顺序 2
    }

    @CrossOrigin
    @GetMapping(value = "/link", produces = "text/event-stream;charset=utf-8")
    @SneakyThrows
    public SseEmitter link() {
        return chatService.link();// TODO: 2023/10/16 执行顺序 1
    }

    @CrossOrigin
    @PostMapping(value = "/stop")
    @SneakyThrows
    public void chatGPT() {
        chatService.stop();// TODO: 2023/10/16 执行顺序 3
    }
}

请求体

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ChatRequest {
    private String question;
}

接口

public interface ChatService {
    void chat(ChatRequest request);

    SseEmitter link();

    void stop();

}

实现类
@Slf4j
@Service
public class ChatServiceImpl implements ChatService {

    static HashMap<String, SseEmitter> map = new HashMap<>();

    @SneakyThrows
    @Override
    public void chat(ChatRequest request) {
        SseEmitter sseEmitter = map.get("222");
        String question = request.getQuestion();
        char[] chars = question.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            sseEmitter.send(SseEmitter.event().id("111").data(chars[i]));
        }
    }

    @SneakyThrows
    @Override
    public SseEmitter link() {

        SseEmitter sseEmitter = new SseEmitter(0L);//设置超时时间,单位为毫秒
        map.put("222", sseEmitter);

        //  >> 回调1:长链接完成后回调接口(即关闭连接时调用)
        sseEmitter.onCompletion(() -> {
            map.remove("222");
            log.info("连接关闭, userId = {},  sessionId = {}, 时间戳 = {}", null, null, System.currentTimeMillis());// TODO: 2023/10/16 执行顺序 4
        });


        //  >> 回调2:出现异常会调用此方法
        sseEmitter.onError(new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) {
                log.info("连接出错, userId = {},  sessionId = {}, 时间戳 = {}", null, null, System.currentTimeMillis());
                sseEmitter.completeWithError(new RuntimeException("SSE 超时了"));
            }
        });


        //  >> 回调3:出现连接超时,会调用此方法
        sseEmitter.onTimeout(() -> {
            log.info("连接超时, userId = {},  sessionId = {}, 时间戳 = {}", null, null , System.currentTimeMillis());
            sseEmitter.completeWithError(new RuntimeException("SSE 超时了"));
        });

        sseEmitter.send(SseEmitter.event().data("操作成功"));
        return sseEmitter;
    }

    @SneakyThrows
    @Override
    public void stop() {
        SseEmitter sseEmitter = map.get("222");
        sseEmitter.send(SseEmitter.event().id("111").data("中断"));
        sseEmitter.complete();
    }
}

终端开两个窗口通过curl验证效果

  • 请求连接的curl
curl -H "Accept: text/event-stream" http://localhost:9033/link

得到应答:
在这里插入图片描述

  • 提问的curl(这个演示的是将输入的文字推送出来):
curl -X POST -H "Content-Type: application/json" -d "{\"question\": \"hhhhh\"}" http://localhost:9033/ask

提问后得到的响应:
在这里插入图片描述

  • mock服务主动断开的curl:
curl -X POST http://localhost:9033/stop

客户端收到的:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值