【问题标题】:How to add query parameter only if there's a value in second request in Retrofit or OkHttpClient interceptor仅当 Retrofit 或 OkHttpClient 拦截器中的第二个请求中有值时如何添加查询参数
【发布时间】:2022-09-29 02:58:53
【问题描述】:

在这个应用程序中,我使用了Blogger API,我有这个获取帖子的方法

@GET
suspend fun getPostList(@Url URL: String): Response<PostList>

这是我使用的基本 URL

const val BASE_URL = \"https://www.googleapis.com/blogger/v3/blogs/$BLOG_ID/posts/\"

当第一次请求时它变成这样

https://www.googleapis.com/blogger/v3/blogs/12345678910/posts/maxResults=20&key=API_KEY

当第二个请求它应该得到一个令牌参数pageToken=ABCDE 导致我需要进行分页,所以我编辑基本网址在 viewModel 中添加 pageToken 参数,然后我再次将它传递给 getPostList 方法

它看起来像这样

https://www.googleapis.com/blogger/v3/blogs/12345678910/posts/maxResults=20&pageToken=ABCDEFG&key=API_KEY

这是我的网络层

private val interceptor : HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
    this.level = HttpLoggingInterceptor.Level.BODY
}

    @Singleton
    @Provides
    fun postAPIService(): PostAPIService {
        return Retrofit.Builder()
            .baseUrl(Constants.BASE_URL)
            .client(
                OkHttpClient.Builder().readTimeout(
                    15, TimeUnit.SECONDS
                ).connectTimeout(15, TimeUnit.SECONDS)
                    .addNetworkInterceptor(interceptor)
                    .addInterceptor { chain ->
                        val url = chain
                            .request()
                            .url
                            .newBuilder()
                            .addQueryParameter(\"maxResults\", Constants.MAX_RESULT)
                            .addQueryParameter(\"key\", Constants.API_KEY)
                            .build()
                        chain.proceed(chain.request().newBuilder().url(url)
                            .build())
                    }.build()

            )
            .addConverterFactory(GsonConverterFactory.create())
            .build().create(PostAPIService::class.java)
    }
}

在视图模型层:

    /** RETROFIT **/
    var postsResponse: MutableLiveData<NetworkResult<PostList>> = MutableLiveData()
    var postListResponse: PostList? = null

    val label = MutableLiveData<String>()
    var finalURL: MutableLiveData<String> = MutableLiveData()
    private val token = MutableLiveData<String?>()

private suspend fun getPostsSafeCall() {

        postsResponse.postValue(NetworkResult.Loading())

        Log.e(TAG, \"getPostsSafeCall finalURL is ${finalURL.value!!}\")

        if (hasInternetConnection()) {
            try {

                if (finalURL.value.isNullOrEmpty()) {
                    finalURL.postValue(BASE_URL)
                }

                val response = mainRepository.remoteDataSource.getPostList(finalURL.value!!)
                postsResponse.value = handlePostsResponse(response)

            } catch (exception: Exception) {
                postsResponse.postValue(NetworkResult.Error(exception.message.toString()))
//                Log.e(TAG, e.message + e.cause)
                if (exception is HttpException) {
                    errorCode.postValue(exception.code())
                    Log.e(TAG, \"getPostsSafeCall: errorCode $errorCode\")
                    Log.e(TAG, \"getPostsSafeCall: ${exception.message.toString()}\")
                }
            }
        } else {
            postsResponse.postValue(NetworkResult.Error(\"No Internet Connection.\"))
        }
    }


private fun handlePostsResponse(response: Response<PostList>): NetworkResult<PostList> {
        if (response.isSuccessful) {

            token.value = response.body()?.nextPageToken

            Log.d(TAG, \"handlePostsResponse: token = ${response.body()?.nextPageToken.toString()}\")

            response.body()?.let { resultResponse ->
                Log.d(
                    TAG, \"handlePostsResponse: old token is: ${token.value} \" +
                            \"new token is: ${resultResponse.nextPageToken}\"
                )

                finalURL.postValue(
                    BASE_URL + \"&pageToken=${token.value}\"
                )

                if (postListResponse == null) {
                    postListResponse = resultResponse
                } else {
                    val oldPosts = postListResponse?.items
                    val newPosts = resultResponse.items
                    oldPosts?.addAll(newPosts)
                }

                Log.d(TAG, \"handlePostsResponse: ${token.value}\")
                Log.e(TAG, \"handlePostsResponse finalURL is ${finalURL.value!!}\")

                for (item in resultResponse.items) {
                    insertItem(item)
                }
                return NetworkResult.Success(postListResponse ?: resultResponse)

            }

        } else  {
            if (token.value == null) {
                errorCode.postValue(400)
            } else {
                errorCode.postValue(response.code())
            }

            Log.d(TAG, \"handlePostsResponse: ${response.code().toString()}\")
            Log.d(TAG, \"handlePostsResponse: ${response.headers().toString()}\")
            Log.d(TAG, \"handlePostsResponse: ${response.headers().toString()}\")
//        Log.d(TAG, \"handlePostsResponse: final ${finalURL.value.toString()}\")
            return NetworkResult.Error(
                \"network results of handlePostsResponse ${response.body().toString()}\"
            )
        }
        return NetworkResult.Error(
            \"network results of handlePostsResponse ${response.body().toString()}\"
        )
    }

我需要的

一种注入pageToken参数的方法动态的只有当有一个值(NOT NULL OR EMPTY)来避免最终/基本 URL 中的以下内容时

https://www.googleapis.com/blogger/v3/blogs/4294497614198718393/posts/?maxResults=20&pageToken=null&key=API_KEY

这会导致错误 400 badRequest

{
  \"error\": {
    \"code\": 400,
    \"message\": \"We\'re sorry, but the value for field pageToken was not valid.\",
    \"errors\": [
      {
        \"message\": \"We\'re sorry, but the value for field pageToken was not valid.\",
        \"domain\": \"global\",
        \"reason\": \"invalid\"
      }
    ]
  }
}

我尝试编辑 PostAPIService 方法使其看起来像这样

  @GET(\"posts\")
    suspend fun getPostList(@Query(\"pageToken\") pageToken: String=\"\"): Response<PostList>

并像这样在viewModel中使用它

 val response = if (token.value.isNullOrEmpty()) {
 mainRepository.remoteDataSource.getPostList()
 } else {
mainRepository.remoteDataSource.getPostList(token.value!!)
}

但不幸的是,这也会导致 badRequest 也是因为pageToken=null inBASE_URL

    标签: android kotlin retrofit retrofit2 okhttp


    【解决方案1】:

    由于docs said Retrofit 忽略了空查询值,这意味着您只需从基本 url 中删除 pageToken 并在您的函数中使相应的参数可以为空:

     @GET("posts")
     suspend fun getPostList(@Query("pageToken") pageToken: String? = null): Response<PostList
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      • 2021-08-19
      相关资源
      最近更新 更多