l***@163.com
l***@163.com
  • 发布:2025-06-20 17:44
  • 更新:2025-06-20 22:14
  • 阅读:30

connectEventSource请求sse流,这个接口有可能几毫米返回一条数据,然后我这边拿到数据就更新,就会导致莫名其妙的问题

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: win10

HBuilderX类型: 正式

HBuilderX版本号: 4.66

手机系统: Android

手机系统版本号: Android 14

手机厂商: 小米

手机机型:

页面类型: nvue

vue版本: vue3

打包方式: 离线

项目创建方式: HBuilderX

示例代码:

<template>
<text class="message-content-text" style="color: #fff;font-size: 28rpx;line-height: 1.5;">
{{contents}}
</text>
<text style="color: #fff;" :style="{ opacity }" v-if="isSend">|</text>
</template>

<script setup>
const props = defineProps({
inputMessage: {
type: String,
default: ''
}
})
import { HTTP_REQUEST_URL } from '@/config';
let eventSource : UniEventSource | null = null
let once = true
const contents = ref('')
const getContents = computed(() => contents.value)
const isSend = ref(true)
const opacity = ref(1)
let timer : number | null = null
const setOpacity = () => {
if (timer !== null) clearInterval(timer as number)
timer = setInterval(() => {
opacity.value = opacity.value > 0 ? 0 : 1
}, 500)
}
const emit = defineEmits(['stop', 'updateScrollTop'])
setOpacity()
onUnmounted(() => {
eventSource?.close()
if (timer !== null) clearInterval(timer as number)
})
const handleAPICall = () => {
let displayMessage = '';

    eventSource = uni.connectEventSource({ url: HTTP_REQUEST_URL + '/api/chat/stream' });  

    eventSource?.onMessage(({ data }) => {  
        try {  
            const jsonData = JSON.parseObject(data as string);  
            const output = jsonData?.get("output") as UTSJSONObject | null;  
            const rawText = output?.get("text");  
            const newText = typeof rawText === 'string' ? rawText : '';  
            displayMessage += newText  
            nextTick(() => {  
                if ((displayMessage != '' && displayMessage != null) || (newText != '' && newText != null) && (displayMessage != newText)) {  
                    contents.value = displayMessage  
                    if (isSend.value) {  
                        isSend.value = false;  
                        if (timer !== null) clearInterval(timer as number)  
                    }  
                    nextTick(() => {  
                        emit('updateScrollTop')  
                    })  
                }  
            })  
            // throttledSetContent(displayMessage)  
            // 检查是否是最后一次数据  
            if (output?.get("finish_reason") == 'stop') {  
                emit('updateScrollTop')  
                emit('stop')  
                eventSource?.close(); // 关闭 SSE  
                console.log('displayMessage:', displayMessage);  
            }  
        } catch (e) {  
            console.log(e, '<<>><><><<');  
            uni.showToast({  
                title: '连接错误,已中断连接',  
                icon: 'none'  
            });  
            emit('stop')  
            emit('updateScrollTop')  
            eventSource?.close();  
        }  
    });  

    eventSource?.onError((error : any) => {  
        emit('stop')  
        eventSource?.close();  
        isSend.value = false;  
    });  
};  
watch(() : string => props.inputMessage, (t : string) => {  
    if (t == '' && once) {  
        setTimeout(() => {  
            handleAPICall()  
            once = false  
        }, 100)  
    }  
})  

</script>

<style>

</style>

操作步骤:

<template>
<text class="message-content-text" style="color: #fff;font-size: 28rpx;line-height: 1.5;">
{{contents}}
</text>
<text style="color: #fff;" :style="{ opacity }" v-if="isSend">|</text>
</template>

<script setup>
const props = defineProps({
inputMessage: {
type: String,
default: ''
}
})
import { HTTP_REQUEST_URL } from '@/config';
let eventSource : UniEventSource | null = null
let once = true
const contents = ref('')
const getContents = computed(() => contents.value)
const isSend = ref(true)
const opacity = ref(1)
let timer : number | null = null
const setOpacity = () => {
if (timer !== null) clearInterval(timer as number)
timer = setInterval(() => {
opacity.value = opacity.value > 0 ? 0 : 1
}, 500)
}
const emit = defineEmits(['stop', 'updateScrollTop'])
setOpacity()
onUnmounted(() => {
eventSource?.close()
if (timer !== null) clearInterval(timer as number)
})
const handleAPICall = () => {
let displayMessage = '';

    eventSource = uni.connectEventSource({ url: HTTP_REQUEST_URL + '/api/chat/stream' });  

    eventSource?.onMessage(({ data }) => {  
        try {  
            const jsonData = JSON.parseObject(data as string);  
            const output = jsonData?.get("output") as UTSJSONObject | null;  
            const rawText = output?.get("text");  
            const newText = typeof rawText === 'string' ? rawText : '';  
            displayMessage += newText  
            nextTick(() => {  
                if ((displayMessage != '' && displayMessage != null) || (newText != '' && newText != null) && (displayMessage != newText)) {  
                    contents.value = displayMessage  
                    if (isSend.value) {  
                        isSend.value = false;  
                        if (timer !== null) clearInterval(timer as number)  
                    }  
                    nextTick(() => {  
                        emit('updateScrollTop')  
                    })  
                }  
            })  
            // throttledSetContent(displayMessage)  
            // 检查是否是最后一次数据  
            if (output?.get("finish_reason") == 'stop') {  
                emit('updateScrollTop')  
                emit('stop')  
                eventSource?.close(); // 关闭 SSE  
                console.log('displayMessage:', displayMessage);  
            }  
        } catch (e) {  
            console.log(e, '<<>><><><<');  
            uni.showToast({  
                title: '连接错误,已中断连接',  
                icon: 'none'  
            });  
            emit('stop')  
            emit('updateScrollTop')  
            eventSource?.close();  
        }  
    });  

    eventSource?.onError((error : any) => {  
        emit('stop')  
        eventSource?.close();  
        isSend.value = false;  
    });  
};  
watch(() : string => props.inputMessage, (t : string) => {  
    if (t == '' && once) {  
        setTimeout(() => {  
            handleAPICall()  
            once = false  
        }, 100)  
    }  
})  

</script>

<style>

</style>

预期结果:

实际结果:

报错

bug描述:

就是做一个ai问答功能,connectEventSource请求sse流,这个接口有可能几毫米返回一条数据,然后我这边拿到数据就更新,就会导致莫名其妙的问题,我这边能保证数据什么的都不是空得但就是报空:
ava.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1029)
at java.util.ArrayList$Itr.next(ArrayList.java:982)
at io.dcloud.uniapp.vue.IndexKt.initDepMarkers(index.kt:8723)
at io.dcloud.uniapp.vue.ReactiveEffect$run$1.invoke(index.kt:363)
at io.dcloud.uniapp.vue.IndexKt$setupRenderEffect$2.invoke(index.kt:6535)
at io.dcloud.uniapp.vue.IndexKt$setupRenderEffect$2.invoke(index.kt:6534)
at io.dcloud.uniapp.vue.IndexKt$flushJobs$1.invoke(index.kt:5162)
at java.lang.reflect.Method.invoke(Native Method)
at io.dcloud.uts.UTSPromiseKt$callFunction$invoke$1.invoke(UTSPromise.kt:31)
at io.dcloud.uts.UTSPromiseKt.callFunction(UTSPromise.kt:42)
at io.dcloud.uts.UTSPromiseKt$handleUTSPromise$1.invoke(UTSPromise.kt:439)
at java.lang.reflect.Method.invoke(Native Method)
at io.dcloud.uts.UTSPromiseKt$callFunction$invoke$1.invoke(UTSPromise.kt:31)
at io.dcloud.uts.UTSPromiseKt.callFunction(UTSPromise.kt:42)
at io.dcloud.uts.UTSPromise$Companion$_immediateFn$1.invoke(UTSPromise.kt:367)
at io.dcloud.uts.UTSPromise$Companion$_immediateFn$1.invoke(UTSPromise.kt:366)
at io.dcloud.uts.UTSTimerKt.setTimeout$lambda$0(UTSTimer.kt:95)
at io.dcloud.uts.UTSTimerKt.$r8$lambda$UAyJ1gnsCkiOBi4f4GjC1hFRNNA(Unknown Source:0)
at io.dcloud.uts.UTSTimerKt$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:487)
at java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:307)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1251)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:668)
at java.lang.Thread.run(Thread.java:1012)
14:57:05.249 Possible Unhandled Promise Rejection: ‍[⁠java.util.ConcurrentModificationException⁠]‍ {cause: null, message: null}
还有这个:
[⁠java.lang.NullPointerException⁠]‍ {cause: null, message: null}

2025-06-20 17:44 负责人:无 分享
已邀请:
DCloud_heavensoft

DCloud_heavensoft

要回复问题请先登录注册