springboot2.x使用SSE方式代理或者转发其他流式接口

文章目录

1.需求描述

使用SSE的方式主要还是要跟前端建立一个EventSource的链接,有了这个连接,然后往通道里写入数据流,前端自然会拿到流式数据,写啥拿啥,后端这个对象叫做SseEmitter.

2.代码

2.1.示例controller

java 复制代码
@Slf4j
@RestController
@RequestMapping("/proxy")
public class StreamForwardingController {

    @Autowired
    private ModelService modelService;

    @GetMapping("/sse/reply")
    public SseEmitter sseReply(@RequestBody JSONObject req) {
        try {
            return modelService.call(req);
        } catch (IOException e) {
            log.error("SSE接口异常:{}", e.getMessage());
            return new SseEmitter();
        }
    }
}

2.2.示例service

java 复制代码
public interface ModelService {

    SseEmitter call(JSONObject param) throws IOException;

}

2.3.示例impl

java 复制代码
@Service
@Slf4j
public class ModelServiceImpl implements ModelService {

	/*
	  其实可以自己组装SSE流式数据给前端(参考上篇文章)
	  也可以调用别的流式接口,拿到流数据给前端(下面是这种方式)
	*/
    @Override
    public SseEmitter call(JSONObject param) throws IOException {
        log.info("[SSE]开始调用大模型...");
        log.info("[SSE]请求参数:{}",param.toString());
        
        // 这里是自己的一些参数定义
        String id = RandomUtil.randomString(32);
        String xxx = param.getString("xxx");
        String yyy = param.getString("yyy");

        // 根据过期时间创建SSE对象
        SseEmitter sseEmitter = new SseEmitter(0L);

        // 预处理
        if(StringUtils.isEmpty(xxx) || StringUtils.isEmpty(yyy)){
            log.error("[SSE]请求参数为空");
            sseEmitter.send("error: 请求参数为空");//这里可以不这么做,将报错信息可以发出去
            sseEmitter.complete();//发完有个结束的标识,目的是为了结束连接
            return sseEmitter;
        }

        //组装流式接口请求对象 这里是请求别人家的流式接口的
        JSONObject req = new JSONObject();
        String targetUrl = "http://xxx/x/x/xxx/x/x/x";
        log.info("[SSE]流式接口:{}", targetUrl);
        log.info("[SSE]请求报文:{}", req);

        HttpRequest request = HttpRequest.post(targetUrl)
                .header("Content-Type", ContentType.JSON.toString())
                .body(JSONUtil.toJsonStr(req))
                .timeout(10000);

        // 使用异步请求获取实时数据
        HttpResponse response = request.executeAsync();
        log.info("[SSE]模型状态码:{}", response.getStatus());
        if(response.getStatus() != HttpStatus.HTTP_OK) {
            log.error("[SSE]模型接口异常:{}",response.body());
        }

        //使用新的线程处理响应结果,如果是自己想弄个流式数据给前端返回,也是这个原理
        //循环往sse对象里send就完事了
        new Thread(()->{
            try (BufferedReader reader = new BufferedReader(
            							 new InputStreamReader(
            							 new BufferedInputStream(
            							 response.bodyStream())))) 
            {
                String line;
                while ((line = reader.readLine()) != null) {
                    //System.out.println("line="+line);
                    if(StringUtils.isNotEmpty(line)) sseEmitter.send(line);
                    //else System.out.println("空行");
                }
                log.info("[SSE]模型接口解析完毕.");
                sseEmitter.complete();
            }catch (Exception e){
                log.error("[SSE]模型接口异常:{}", e.getMessage());
            }
        }).start();
        return sseEmitter;//最后记得把sse对象返回给前端
    }
}

3.测试

使用Postman测试即可,没啥特殊配置。

相关推荐
星恒随风4 天前
C++ string 类详解:常用接口、OJ 场景与模拟实现中的深浅拷贝
开发语言·c++·笔记·学习·状态模式
colofullove5 天前
实时游玩页与 WebSocket 状态管理实现
websocket·网络协议·状态模式
夏天测6 天前
业务逻辑漏洞实战:篡改响应包绕过登录,直入后台管理系统
渗透测试·状态模式·业务逻辑漏洞·web 安全·响应包篡改
可乐ea7 天前
【Spring Boot + MyBatis|第7篇】JWT 登录认证与拦截器实现
java·spring boot·后端·mybatis·状态模式
前端不太难7 天前
GPU 集群调度架构解析
架构·状态模式
ShiJiuD6668889997 天前
外卖项目笔记总结上 (后端板块)
状态模式
前端不太难7 天前
当 AI 接管 Workspace:鸿蒙 PC Agent 架构设计实践
人工智能·状态模式·harmonyos
Maimai108088 天前
Web3 前端实时通信如何落地:从 SSE 订阅到行情、订单与账户状态更新
前端·javascript·react.js·前端框架·web3·状态模式
不吃青椒!8 天前
LangGraph 流式事件处理:从实战到体系
ai·langchain·状态模式
前端不太难9 天前
鸿蒙游戏世界模型:实现原理 + Demo实现
游戏·状态模式·harmonyos