欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實現(xiàn)網(wǎng)絡(luò)訪問攔截器的常見方式

 更新時間:2025年07月04日 09:14:29   作者:花花魚  
這篇文章主要為大家詳細介紹了基于Android實現(xiàn)網(wǎng)絡(luò)訪問攔截器的幾種常見方式,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

1、接口訪問鑒權(quán)原型

一般我們在訪問服務(wù)器端的時候,比如登錄成功了,會有一個信息的返回,一般會有一個auth值,也有可能是一個sessionid,這樣我們就可以帶著這個值或者id,去訪問一些需要鑒權(quán)的接口了。

2、客戶端調(diào)用header鑒權(quán)

在android端,我們通常會編寫一些攔截器來進行自動加入header,這樣就可以去自動加入,不需要手工處理。

3、攔截器的方式

方式一(withContext / runBlocking)

每次請求都同步獲取 jsessionId

方式二(CoroutineScope + 緩存)

異步加載并緩存 jsessionId,支持并發(fā)控制

方式三(純 runBlocking)

完全阻塞方式獲取 jsessionId

4、三種方式的對比

1. 方式一:使用 runBlocking 獲取值

適用場景:如果你能確保該攔截器僅運行在非 UI 線程(如 OkHttp 的后臺線程),可以接受。

不推薦原因:

若攔截器在主線程執(zhí)行(如某些測試或調(diào)試場景),會導(dǎo)致卡頓甚至 ANR。

每次請求都重新獲取 JSESSIONID,效率低且無必要。

val jsessionId = runCatching {
    runBlocking(dispatcher) {
        appDataStore.getJSessionId().firstOrNull()
    }
}.getOrNull()

2. 方式二:使用 CoroutineScope + 緩存(推薦)

異步加載,不會阻塞主線程。

使用緩存避免頻繁讀取數(shù)據(jù)源,提高性能。

支持并發(fā)控制(通過 synchronized)。

實現(xiàn)了 Closeable 接口,便于資源釋放。

推薦作為生產(chǎn)代碼使用,尤其適合需要高性能、穩(wěn)定性強的 App。

private var cachedJSessionId: String? = null
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

private fun updateJSessionId() {
    scope.launch {
        appDataStore.getJSessionId().firstOrNull()?.let {
            synchronized(updateLock) {
                cachedJSessionId = it
            }
        }
    }
}

3. 方式三:純 runBlocking 同步獲取

在任何上下文中使用都會導(dǎo)致線程阻塞。

如果 appDataStore.getJSessionId() 是耗時操作(如從磁盤讀?。?,極易造成 ANR。無法應(yīng)對異常情況。

val jsessionId: String? = runBlocking {
    appDataStore.getJSessionId().firstOrNull()
}

5、相關(guān)代碼

方式一:使用 withContext

/**
 * 攔截器,用于添加 JSESSIONID 到請求頭
 * 在指定的協(xié)程調(diào)度器 dispatcher 中,從 appDataStore 獲取 JSessionId 的值,并忽略可能的異常,最終將結(jié)果賦值給 jsessionId。
 * 具體解釋如下:
 * runCatching { ... }:捕獲代碼塊中的異常,避免程序崩潰。
 * runBlocking(dispatcher) { ... }:在指定的協(xié)程調(diào)度器中啟動一個阻塞式協(xié)程。
 * appDataStore.getJSessionId().firstOrNull():獲取 JSessionId 的第一個值,若無數(shù)據(jù)則返回 null。
 * .getOrNull():從 runCatching 的結(jié)果中取出值,若發(fā)生異常則返回 null。
 */

class AuthInterceptor @Inject constructor(
    private val appDataStore: AppDataStore,
    private val dispatcher: CoroutineDispatcher = Dispatchers.IO
) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        // 使用 withContext 在 IO 線程獲取數(shù)據(jù)
        val jsessionId = runCatching {
            runBlocking(dispatcher) {
                appDataStore.getJSessionId().firstOrNull()
            }
        }.getOrNull()

        val newRequest = if (jsessionId != null) {
            val cookie = request.header("Cookie").orEmpty()
            val newCookie = if (cookie.isEmpty()) {
                "JSESSIONID=$jsessionId"
            } else {
                "$cookie; JSESSIONID=$jsessionId"
            }

            request.newBuilder()
                .header("Cookie", newCookie)
                .build()
        } else {
            request
        }

        return chain.proceed(newRequest)
    }
}

該 Kotlin 代碼定義了一個 AuthInterceptor類,用于在發(fā)起網(wǎng)絡(luò)請求時自動添加 `JSESSIONID` 到 Cookie 中。其邏輯如下:

1. 從 AppDataStore中異步獲取 `JSESSIONID`;

2. 若存在 `JSESSIONID`,則將其拼接到請求頭的 `Cookie` 字段中;

3. 最終繼續(xù)執(zhí)行修改后的請求。

方式二:使用 CoroutineScope

class AuthInterceptor @Inject constructor(
    private val appDataStore: AppDataStore
) : Interceptor, Closeable {

    private var cachedJSessionId: String? = null
    private val updateLock = Any()
    private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

    init {
        updateJSessionId()
    }

    private fun updateJSessionId() {
        scope.launch {
            appDataStore.getJSessionId().firstOrNull()?.let {
                synchronized(updateLock) {
                    cachedJSessionId = it
                }
            }
        }
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        var jsessionId = cachedJSessionId
        if (jsessionId == null) {
            synchronized(updateLock) {
                jsessionId = cachedJSessionId
                if (jsessionId == null) {
                    updateJSessionId()
                    return chain.proceed(request)
                }
            }
        }

        val cookieHeader = request.header("Cookie").orEmpty()
        val newCookie = if (cookieHeader.isEmpty()) {
            "JSESSIONID=$jsessionId"
        } else {
            "$cookieHeader; JSESSIONID=$jsessionId"
        }

        val newRequest = request.newBuilder()
            .header("Cookie", newCookie)
            .build()

        return chain.proceed(newRequest)
    }

    // 實現(xiàn) Closeable 接口,確保資源釋放
    override fun close() {
        scope.cancel()
    }
}

推薦作為生產(chǎn)代碼使用,尤其適合需要高性能、穩(wěn)定性強的 App。

該 Kotlin 代碼實現(xiàn)了一個 AuthInterceptor用于在 HTTP 請求中自動添加 `JSESSIONID` Cookie。其功能如下:

1. **構(gòu)造與初始化**:通過依賴注入獲取 AppDataStore用于讀取會話 ID,并在初始化時嘗試更新會話 ID。

2. **intercept 函數(shù)**:

   - 若已有緩存的 `JSESSIONID`,則將其添加到請求頭的 Cookie 中;

   - 若沒有緩存,則重新加載會話 ID;

   - 使用鎖保證線程安全。

3. **updateJSessionId 函數(shù)**:使用協(xié)程從 AppDataStore 異步加載會話 ID 并緩存。

4. **close 函數(shù)**:取消協(xié)程作用域,釋放資源。

整體作用:為每個請求自動注入最新的 `JSESSIONID`,確保會話狀態(tài)有效。

方式三:runBlocking阻塞性獲取

class AuthInterceptor @Inject constructor(
    private val appDataStore: AppDataStore
) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()

        // 在攔截器中同步獲取 jsessionid(假設(shè)可以阻塞)
        val jsessionId: String? = runBlocking {
            appDataStore.getJSessionId().firstOrNull()
        }

        // 構(gòu)建新的請求,添加 cookie(僅當(dāng) jsessionId 存在時)
        val newRequest = request.newBuilder().apply {
            if (jsessionId != null) {
                // 獲取現(xiàn)有 Cookie 并追加新的 JSESSIONID
                val existingCookies = request.header("Cookie")
                val newCookie = "JSESSIONID=$jsessionId"

                val finalCookie = if (existingCookies.isNullOrEmpty()) {
                    newCookie
                } else {
                    "$existingCookies; $newCookie"
                }

                addHeader("Cookie", finalCookie)
            }
        }.build()

        return chain.proceed(newRequest)
    }

}

該 Kotlin 代碼定義了一個 AuthInterceptor 攔截器,其功能是:

從 AppDataStore 中同步獲取 jsessionId(使用 runBlocking 阻塞等待);

若 jsessionId 存在,則將其添加到 HTTP 請求頭的 Cookie 字段中;

最終構(gòu)建新請求并繼續(xù)攔截器鏈的執(zhí)行。

作用:為每個請求自動添加會話標識 JSESSIONID。

6、總結(jié)

綜合上述幾種方式,其實測試下來都是可以的,基本上是沒有什么區(qū)別,但是如果考慮綜合因素,或者多環(huán)境下的適應(yīng)性,還是考慮用使用 CoroutineScope + 緩存(推薦)。

到此這篇關(guān)于Android實現(xiàn)網(wǎng)絡(luò)訪問攔截器的常見方式的文章就介紹到這了,更多相關(guān)Android攔截器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論