在實際開發中,我們可能會遇到一些流式數據處理的場景,比如接收來自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 內容,并將其原樣中轉給前端頁面或客戶端。這種情況下,傳統的 RestTemplate
緩存機制會導致數據必須等待全部接收完畢后再處理,違背了流式傳輸的初衷。
本文將介紹如何在 Spring Boot 2.7.x 中使用 RestTemplate
實現一個流式響應的中轉接口。
一、關鍵點說明
-
禁用請求緩沖:
通過SimpleClientHttpRequestFactory#setBufferRequestBody(false)
禁用緩沖,確保流式傳輸生效。 -
設置響應為 SSE 格式:
設置HttpServletResponse
的響應頭為text/event-stream
,支持前端基于 EventSource 的實時響應。 -
使用 RestTemplate.execute 方法:
通過RestTemplate.execute()
方法自定義RequestCallback
和ResponseExtractor
實現對輸入輸出流的精細控制。
二、完整代碼實現
/*** 處理流式響應的HTTP請求方法(流式響應, Spring Boot 2.7.x 兼容)** @param requestBody 請求體內容* @param url 請求URL* @param httpMethod 請求方法* @param response HttpServletResponse,用于直接返回流數據*/
public static void executeStreamingRequest(Map<String, Object> requestBody,String url,HttpMethod httpMethod,HttpServletResponse response) throws IOException {// 1. 配置RestTemplate(啟用流式)SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();requestFactory.setBufferRequestBody(false); // 關鍵:禁用請求緩沖requestFactory.setConnectTimeout(30000);requestFactory.setReadTimeout(60000);RestTemplate restTemplate = new RestTemplate(requestFactory);// 2. 設置請求頭HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);// 3. 執行流式請求try {log.info("【開始流式請求】URL: {}", url);restTemplate.execute(URI.create(url),httpMethod,new RequestCallback() {@Overridepublic void doWithRequest(ClientHttpRequest request) throws IOException {request.getHeaders().putAll(headers);if (requestBody != null) {new ObjectMapper().writeValue(request.getBody(), requestBody);}}},new ResponseExtractor<Void>() {@Overridepublic Void extractData(ClientHttpResponse clientResponse) throws IOException {// 設置響應頭response.setContentType("text/event-stream");response.setCharacterEncoding("UTF-8");// 流式傳輸try (InputStream is = clientResponse.getBody();OutputStream os = response.getOutputStream()) {byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {os.write(buffer, 0, bytesRead);os.flush(); // 立即刷新}}return null;}});} catch (RestClientException e) {log.error("流式請求失敗", e);response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);response.getWriter().write("服務調用失敗: " + e.getMessage());}
}
三、使用場景舉例
-
轉發 OpenAI 的流式 API 響應
-
轉發后端 AI 推理接口的逐步響應
-
轉發日志、進度等后臺任務推送數據
四、注意事項
-
保證上下游接口支持長連接和流式傳輸
-
防止瀏覽器緩沖影響效果,前端建議使用
EventSource
或fetch + reader
模式消費 -
若上游響應為分塊傳輸(chunked),務必確保 header 中包含
Transfer-Encoding: chunked
一線網資源-全網一站式平臺