java 创建和请求sse服务

本文介绍了如何在SpringBoot项目中使用OkHttp库创建一个支持Server-SentEvents(SSE)的RESTful服务,并通过示例展示了如何发送和接收SSE事件。同时讨论了OkHttp的连接管理问题,指出在某些场景下无需手动关闭连接。
摘要由CSDN通过智能技术生成

主要依赖

<!--spring-boot父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
    </parent>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>com.squareup.okhttp3</groupId>
	<artifactId>okhttp</artifactId>
	<version>4.2.0</version>
</dependency>
<dependency>
	<groupId>com.squareup.okhttp3</groupId>
	<artifactId>okhttp-sse</artifactId>
	<version>4.2.0</version>
</dependency>

服务

package cn;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.Map;

@RestController
public class SseController {
    @PostMapping(value = "/sse", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
    public SseEmitter handleSse(@RequestBody Map<String, Object> data) {
        System.out.println(data);
        SseEmitter emitter = new SseEmitter();
        // 模拟一个长时间运行的任务,每秒发送一个事件
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("开始响应 " + i);
                try {
                    emitter.send(System.currentTimeMillis());
                } catch (IOException e) {
                    // 如果客户端断开连接,我们需要关闭emitter
                    emitter.completeWithError(e);
                }
            }
            emitter.complete();


        }).start();
        return emitter;
    }
}

请求

package cn.demo;

import cn.hutool.json.JSONUtil;
import okhttp3.*;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;

import java.util.Arrays;
import java.util.HashMap;

public class Test_1 {
    public static void main(String[] args) throws Exception {
        OkHttpClient client = new OkHttpClient.Builder().build();

        EventSource.Factory factory = EventSources.createFactory(client);
        // 请求体
        HashMap<String, Object> map = new HashMap<>();
        map.put("prompt", "哈喽,你好");
        map.put("history", Arrays.asList());
        map.put("temperature", 0.9);
        map.put("top_p", 0.7);
        map.put("max_new_tokens", 4096);
        String json = JSONUtil.toJsonStr(map);
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
        // 请求对象
        Request request = new Request.Builder()
                .url("http://localhost:8080/sse")
                .post(body)
                .build();

        // 自定义监听器
        EventSourceListener eventSourceListener = new EventSourceListener() {
            @Override
            public void onOpen(EventSource eventSource, Response response) {
                System.out.println("开启");
                super.onOpen(eventSource, response);
            }

            @Override
            public void onEvent(EventSource eventSource, String id, String type, String data) {
                //   接受消息 data
                System.out.println("数据data "+data);
                super.onEvent(eventSource, id, type, data);
            }

            @Override
            public void onClosed(EventSource eventSource) {
                System.out.println("关闭");
                //super.onClosed(eventSource);
            }

            @Override
            public void onFailure(EventSource eventSource, Throwable t, Response response) {
                System.out.println("失败");
                super.onFailure(eventSource, t, response);
            }
        };

        // 创建事件
        EventSource eventSource = factory.newEventSource(request, eventSourceListener);
        //client.dispatcher().executorService().shutdown();

    }

}

说明

请求连接没有立即关闭

当请求完服务后,okhttp本身并不会直接关闭,它有后台挂起的线程。
这里的关闭不是必须的,如果你的应用需要立即关闭连接,释放资源,可以使用最后一行注释的代码。
EventSource eventSource = factory.newEventSource(request, eventSourceListener);这行代码我在window10上循环了50000次,并没有看到明显的资源占用,似乎真的没有必要关闭。
在这里插入图片描述

参考官网 https://square.github.io/okhttp/5.x/okhttp/okhttp3/-ok-http-client/index.html

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Java 中返回 SSE(Server-Sent Events),可以使用 Java 8 中的 HTTP 服务器(HttpServer)和 HttpServerResponse 类的 sendEvent() 方法。 以下是一个简单的 Java 代码示例,演示如何使用 HttpServer 和 HttpServerResponse 返回 SSE: ```java import java.io.IOException; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class SSEServer { public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); server.createContext("/sse", new SSEHandler()); server.setExecutor(null); server.start(); } static class SSEHandler implements HttpHandler { public void handle(HttpExchange exchange) throws IOException { exchange.getResponseHeaders().set("Content-Type", "text/event-stream"); exchange.getResponseHeaders().set("Cache-Control", "no-cache"); exchange.getResponseHeaders().set("Connection", "keep-alive"); String data = "data: {\"message\": \"hello world\"}\n\n"; exchange.sendResponseHeaders(200, data.length()); while (true) { exchange.getResponseBody().write(data.getBytes()); exchange.getResponseBody().flush(); try { Thread.sleep(1000); } catch (InterruptedException e) { break; } } exchange.getResponseBody().close(); } } } ``` 在上面的代码中,我们创建了一个 HttpServer 对象,并将其绑定到本地主机的 8080 端口。我们还创建了一个 SSEHandler 类,它实现了 HttpHandler 接口,用于处理客户端的 HTTP 请求。在 SSEHandler 的 handle() 方法中,我们设置了响应头,指定了返回内容的类型为 text/event-stream,并启用了连接保持活动。然后,我们使用 sendResponseHeaders() 方法发送响应头,并在一个无限循环中,使用 getResponseBody().write() 方法发送 SSE 事件消息。在本例中,我们每秒钟发送一次事件消息,包含一个 JSON 对象,其中包含一个简单的消息。最后,我们使用 getResponseBody().close() 方法关闭响应流。 希望这个示例能够帮助您理解如何在 Java 中返回 SSE。如果您还有其他问题,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值