Hilt结合SocketIO时如何获取最新accessToken及管理连接
使用Hilt实现Socket功能的问题及解决方案
现有代码实现
RepositoryModule
@Module @InstallIn(SingletonComponent::class) object RepositoryModule { @Provides fun provideSocketRepository(socket: Socket): SocketRepository { return SocketRepository(socket) } }
ServiceModule
@Module @InstallIn(SingletonComponent::class) object ServiceModule { @Provides fun provideSocket(): Socket { logd("socket: accessToken: ${Common.accessToken}") val options = IO.Options().apply { timeout = 30000 reconnection = true reconnectionDelay = 1000 reconnectionAttempts = 300 transports = arrayOf(WebSocket.NAME) extraHeaders = mapOf( "Authorization" to listOf("Bearer ${Common.accessToken}"), "Content-Type" to listOf("application/json"), "identity" to listOf("app") ) } return IO.socket(UrlType.BACK_OFFICE_SERVER.getUrl(), options) } }
问题及解决方案
问题1:获取更新后的accessToken并更新Socket实例
当前Common.accessToken是全局变量,登录后更新无法同步到已注入的Socket实例,可按以下方式重构:
用Hilt注入的Token管理类替换全局变量
定义单例Token管理类,统一处理Token的存储与更新:@Singleton class TokenManager { var accessToken: String? = null private set fun updateToken(newToken: String) { accessToken = newToken } }在Hilt模块中提供该实例:
@Module @InstallIn(SingletonComponent::class) object TokenModule { @Provides fun provideTokenManager(): TokenManager = TokenManager() }实现动态更新的SocketProvider
不再直接提供Socket实例,而是通过SocketProvider管理Socket的创建与更新:@Singleton class SocketProvider @Inject constructor( private val tokenManager: TokenManager ) { private var currentSocket: Socket? = null fun getSocket(): Socket { val token = tokenManager.accessToken ?: throw IllegalStateException("Token未初始化") // 检查现有Socket的Token是否过期,过期则销毁重建 currentSocket?.let { oldSocket -> val oldTokenHeader = oldSocket.options().extraHeaders["Authorization"].orEmpty() if (!oldTokenHeader.contains("Bearer $token")) { oldSocket.disconnect() currentSocket = null } } return currentSocket ?: run { val options = IO.Options().apply { timeout = 30000 reconnection = true reconnectionDelay = 1000 reconnectionAttempts = 300 transports = arrayOf(WebSocket.NAME) extraHeaders = mapOf( "Authorization" to listOf("Bearer $token"), "Content-Type" to listOf("application/json"), "identity" to listOf("app") ) } IO.socket(UrlType.BACK_OFFICE_SERVER.getUrl(), options).also { currentSocket = it } } } // 登录更新Token后调用,触发Socket重建 fun onTokenUpdated() { currentSocket?.disconnect() currentSocket = null } }修改Repository依赖SocketProvider
@Module @InstallIn(SingletonComponent::class) object RepositoryModule { @Provides fun provideSocketRepository(socketProvider: SocketProvider): SocketRepository { return SocketRepository(socketProvider) } }在
SocketRepository中,每次使用Socket时通过socketProvider.getSocket()获取最新实例。
问题2:断开后重新连接的可行性
直接调用socket.disconnect()(不置为null)后再调用socket.connect()是可行的,但需注意:
- Socket.IO实例本身支持多次连接/断开操作,未销毁的实例调用
connect()会重新发起连接请求。 - 但这种方式不会自动更新Socket的header配置,如果Token已更新,旧实例的请求头仍会使用旧Token,因此建议结合上述
SocketProvider方案,在Token更新时重建Socket实例。 - 需监听Socket连接状态,避免重复调用
connect()引发异常。
内容的提问来源于stack exchange,提问作者c-an
相关产品推荐
相关产品推荐

