文章目录
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
测试即可,没啥特殊配置。