使用okHttp3发送sse请求,当事件为finish的时候,如何接收附加的数据?

新手上路,请多包涵

问题描述

当前需要调用一个AI的接口,使用的工具是okHttp3,请求的方式是SSE。当事件状态是finish的时候,对方的响应事件中会携带一个附加的数据(meta)。结构如图:
image.png
在传入的监听器中,onEvent()方法打印响应的data当状态是finish是,打印到的数据是空的,如下图:image.png
第一张图的来源是在初始化htttp客户端的时候加的一个网络请求拦截器打印出的信息,第二张图是代码中打印的log日志。
我的问题是为什么在onEvent()中接收不到meta的数据呢?应该如何接收呢?

问题出现的环境背景及自己尝试过哪些方法

1.首先确定了对方服务在finish状态的时候是一定响应了meta数据的。
2.查询过一些资料,尝试从将data转变为对象,取获取meta,但是也没有结果,是空的。
3.查询过一些其他的系统的源码,发现他们就是从data中获取的meta的数据,我也做同样的尝试,但是没有获取到。

相关代码

发送请求的代码:

    
    public void chat(ModelEnum model, String content, WebSocketEventSourceListener listener) {
        // 初始化客户端
        OkHttpClient okHttpClient = initOkHttpClient();
        RequestBody requestBody = getRequestBody("你只需要回答'收到'两个字就可以了");
        Request request = new Request.Builder()
                .url(getRequestUrl(model))
                .header("Authorization", createToken())
                .header("Accept", "text/event-stream")
                .post(requestBody)
                .build();
        RealEventSource eventSource = new RealEventSource(request, listener);
        eventSource.connect(okHttpClient);
    }

    private OkHttpClient initOkHttpClient() {
        // 初始化客户端
        return new OkHttpClient
                .Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(600, TimeUnit.SECONDS)
                .readTimeout(600, TimeUnit.SECONDS)
                .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
                .build();
    }

监听器代码:

public class WebSocketEventSourceListener extends EventSourceListener {

    @Override
    public void onOpen(EventSource eventSource, Response response) {
        log.info("ListenerOnOpen============={}", "建立sse连接");
    }

    @Override
    public void onEvent(EventSource eventSource, String id, String type, String data) {
        log.info("ListenerOnEvent========== id:{}, type: {}, data: {}", id, type, data);
    }

    @Override
    public void onClosed(EventSource eventSource) {
        log.info("ListenerOnClose========== {}", "连接sse关闭");
    }

    @Override
    public void onFailure(EventSource eventSource, Throwable t, Response response) {

    }
}

在此段代码中onEvent()会接收响应的数据。单是在状态是finish的时候却收不到附加的数据。

你期待的结果是什么?实际看到的错误信息又是什么?

能够在onEvent()中收到meta的数据,实际并没有收到。

阅读 4.3k
avatarAI BotBETA

这个问题可能是由于服务器在发送 "finish" 事件时,没有正确地包含 meta 数据。首先,你需要确认服务器是否确实在这个事件中发送了 meta 数据。如果没有,那么你可能需要与服务器开发者进行交流,让他们在 "finish" 事件中包含 meta 数据。

然而,如果你确定服务器发送了 meta 数据,但你的客户端无法接收到,那么问题可能在于你的监听器实现。你的 WebSocketEventSourceListener 类的 onEvent 方法只接收了 String 类型的 data 参数,这可能不足以接收复杂的 JSON 数据(如果 meta 数据是 JSON 格式的话)。

你可以尝试将 data 参数的类型从 String 更改为 JsonNode,这样你可以直接解析这个 JSON 对象。在 okHttp 中,你可以使用 ObjectMapper 来解析 JSON。以下是如何修改 onEvent 方法的示例:

@Override
public void onEvent(EventSource eventSource, String id, String type, JsonNode data) {
    log.info("ListenerOnEvent========== id:{}, type: {}, data: {}", id, type, data);
    // 如果需要,你可以在这里处理 data
}

此外,你也需要确保服务器发送的 JSON 数据格式正确,并且能够被你的 ObjectMapper 正确解析。如果服务器发送的 JSON 数据格式有误,或者你的 ObjectMapper 不够强大,那么你可能需要在解析数据时处理异常。

以上这些步骤应该可以帮助你解决问题。如果问题依然存在,那么你可能需要进一步检查你的网络连接或服务器状态。

2 个回答

SSE 的规范中明确指出,每个事件的结构中的 field 只能是以下几个取值:

  • event
  • data
  • id
  • retry

所有其他的字段名都会被忽略。

https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_...

显然 OkHttp 在解析事件时遵守了此规范。从源码中我们也可以看出这一点:

https://github.com/square/okhttp/blob/okhttp_3.14.x/okhttp-sse/src/main/java/okhttp3/internal/sse/ServerSentEventReader.java#L55-L102

所以你这里的问题是上游系统使用了非标准的 SSE 协议。如果上游服务不做修改的话,你只能从底层的 HttpClient 自己动手撸一个 Parser 来处理这种特殊场景了。

新手上路,请多包涵

是不是可以放在响应头里面完成呢

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏