【Java】SpringBoot模拟流式输出,前端使用流式接收数据并打印
现在AI的接口由于生成内容比较慢都是采用的流式输出的方式。这里将模拟一下流式输出。
后端接口
import cn.hutool.json.JSONUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping("/stream")
public ResponseEntity<StreamingResponseBody> streamData() {
Map<String, String> map = new HashMap<>();
map.put("content", "内容");
StreamingResponseBody responseBody = outputStream -> {
try (PrintWriter writer = new PrintWriter(outputStream)) {
for (int i = 0; i < 10; i++) {
map.put("content", "内容:" + i);
writer.println(JSONUtil.toJsonStr(map));
writer.flush();
// 模拟一些延迟
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
// 指示这是一个流式响应
headers.setContentLength(-1L);
return new ResponseEntity<>(responseBody, headers, HttpStatus.OK);
}
}
传统非流式-前端
url = 'http://127.0.0.1:8080/test/stream'
async function getResp(){
const startTime = performance.now();
console.log("非流式输出")
const resp = await fetch(url,{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: '讲个笑话'
})
});
const msg = await resp.text();
console.log(msg)
const endTime = performance.now();
console.log(`执行耗时: ${endTime - startTime} ms`);
}
getResp()
测试结果如下,程序会等待所有内容都返回了,才输出内容
流式-前端
async function getRespStream(){
console.log("流式输出")
const resp = await fetch(url,{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: '讲个笑话'
})
});
const reader = resp.body.getReader();
while(1){
// value 是类型化数组
const textDecoder = new TextDecoder()
const {done,value} = await reader.read();
if(done){
break
}
const str = textDecoder.decode(value)
console.log(str)
}
}
getRespStream()
可以看到后端只要输出一段内容前端就会打印一段内容。