?背景:
使用okhttp框架進行網絡訪問時,一般會使用?HttpLoggingInterceptor 打印請求和響應的log。在使用okhttp訪問AI大模型時,如果選擇流式輸出,那么響應的body數據使用的SSE技術,服務異步發送大模型生成的增量token,使用HttpLoggingInterceptor攔截后,會在所有數據接收完成后一次打印完,業務邏輯處也是在log打印完后,才集中收到全部的內容,達不到流式返回的效果。
優化方案:
優化的思路是將body 流攔截打印,然后重新構建response,responsebody和inputstream。將真實的body數據重新寫入到重新構建的responsebody流里面,這樣業務端就會實時收到流式返回的內容。下面是攔截打印body部分的代碼:
@Override
public Response intercept(@NotNull Chain chain) throws IOException {Response response = chain.proceed(chain.request());PipedOutputStream pipedOutputStream = new PipedOutputStream();PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);BufferedSource cloneSource = Okio.buffer(Okio.source(pipedInputStream));ResponseBody cloneBody = ResponseBody.create(cloneSource, response.body().contentType() , response.body().contentLength());Response cloneResponse = response.newBuilder().body(cloneBody).build();BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(pipedOutputStream));InputStream inputStream = response.body().byteStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));new Thread(() -> {String line;while (true) {try {if ((line = reader.readLine()) == null) break;} catch (IOException e) {e.printStackTrace();break;}System.out.println(">>>>>>>>>>>>> log intercept:" + line);try {writer.write(line);writer.write("\r\n");writer.flush();} catch (IOException e) {e.printStackTrace();}}try {writer.close();} catch (IOException e) {e.printStackTrace();}System.out.println("log intercept end");}).start();return cloneResponse;
}