流式输出写法
后台使用 Server-Sent Events 技术,简称 SSE , 是一种基于 HTTP 协议的服务器推送技术,允许服务器向客户端发送数据和信息。与 WebSocket 不同,SSE 是一种单向通信方式,只有服务器可以向客户端推送消息。SSE 是 HTML5 规范的一部分,使用非常简单,主要由服务端与浏览器端的通讯协议(HTTP协议)和 EventSource 接口来处理 Server-sent events 组成,服务器端的响应的内容类型是“text/event-stream”。
后台代码:
package com.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; /** * @return */ @Controller @Slf4j public class ChatgptController { @Autowired private ResourceLoader resourceLoader; @RequestMapping("/article") public void sendArticle(HttpServletResponse res) throws Exception { //流式输出请求头参数 res.setContentType("text/event-stream;charset=UTF-8"); String resourcePath = "other/预备好的文本文件.txt"; Resource resource = new ClassPathResource(resourcePath); InputStream inputStream = resource.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { // 这里用空格来将一行内容分为多个单词输出 String delimiter = " "; String[] words = line.split(delimiter); // 为了支持将中文句子分为单个汉子输出 if (words.length == 1) { delimiter = ""; words = line.split(delimiter); } for (int i = 0; i < words.length; i++) { // 每次只输出一个词,每个片段以data: 开头,以\n\n结尾 res.getWriter().write("data: " + words[i] + delimiter + "\n\n"); res.getWriter().flush(); // 控制输出速率,如果不设置,则一次性全部输出,如果文件过大,直接卡死 Thread.sleep(100); } // 由于每次读的是一行数据,因此输出一个换行 res.getWriter().write("data: </br>\n\n"); } // 也用[done]来标识结束 res.getWriter().write("data: [done]\n\n"); res.getWriter().flush(); } }
前端代码:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>流式输出接收方式</title> </head> <body> <button type="button" onclick="output()">输出文章</button> <div id="message"></div> <script> function output() { let source = new EventSource( 'http://localhost:8180/cmhkevent/article'); let innerHTML = ''; source.onmessage = function(e) { if(e.data == '[done]') { source.close(); } else { innerHTML += e.data; document.getElementById("message").innerHTML = innerHTML; } }; } </script> </body> </html>
感谢原作者:https://zhuanlan.zhihu.com/p/634018241?utm_id=0