Expo构建的React Native中react-native-sse接收SSE需先开内嵌浏览器,求原因
问题场景
我们基于Expo构建的React Native应用,使用binaryminds/react-native-sse库通过XMLHttpRequest(XHR)轮询后端WebFlux的SSE端点接收通知。当前遇到异常:后端已确认识别订阅者并发送SSE消息,但XHR的onreadystatechange回调始终未触发,导致无法接收通知。但如果在初始化XHR请求前,先调用Linking.openURL打开应用内浏览器,SSE功能就会恢复正常,能正常接收通知。
打开应用内浏览器的代码如下:
import { Linking } from 'react-native' Linking.openURL(someURL)
可能的原因分析
1. Expo网络栈延迟初始化
Expo在iOS和Android上的网络实现依赖系统组件(比如iOS的WKWebView、Android的OkHttp),默认情况下应用启动后,底层网络栈可能并未完全初始化完成。而调用Linking.openURL会触发系统浏览器组件的加载,连带完成了网络栈的全量初始化,使得后续的XHR请求能正常建立连接并触发回调。
2. 网络连接池/缓存状态未激活
未打开浏览器时,应用的网络连接池可能处于未激活状态,或者跨域请求的某些隐式配置(如CORS缓存头、会话状态)未正确初始化,导致XHR请求挂起无响应。打开浏览器后,系统的网络缓存、连接池被激活,后续XHR请求能正常与后端建立长连接并接收SSE消息。
3. react-native-sse库的环境依赖
react-native-sse库内部的XHR逻辑可能依赖某些全局网络环境变量或系统状态,这些状态只有在浏览器组件被加载后才会被正确设置。比如库可能间接使用了WebView相关的API,而这些API需要浏览器组件初始化后才能正常工作。
验证与解决方向
- 提前触发网络栈初始化:在应用启动时,发起一个简单的XHR请求(比如请求后端健康检查接口),手动触发网络栈初始化,替代打开浏览器的操作:
import { useEffect } from 'react'; useEffect(() => { // 初始化网络栈的简单请求 const initRequest = new XMLHttpRequest(); initRequest.open('GET', 'https://your-backend-domain/health'); initRequest.onload = () => { console.log('网络栈初始化完成,可启动SSE订阅'); // 这里初始化你的react-native-sse订阅逻辑 }; initRequest.onerror = () => { console.log('初始化请求失败,可重试'); }; initRequest.send(); }, []);
检查SSE库配置:确认
react-native-sse的初始化参数,比如是否开启withCredentials,尝试调整该参数,看是否影响回调触发。排查网络权限与代理:在Android设备上,检查应用是否开启了网络权限,以及是否存在系统代理导致XHR请求异常;Expo Go调试模式下,可切换到生产构建模式测试,排除调试环境的网络差异。
内容的提问来源于stack exchange,提问作者Tom B.

