Retrofit中@QueryMap含空格参数的原样传递问题
问题:Retrofit QueryMap参数空格被自动编码,无法原样发送
接口定义
@GET("restful/api/search") suspend fun librariesSearchBook( @Header("Authorization") access_token: String, @QueryMap(encoded = true) fData: Map<String, String>, @Query("term") term:String, @Query("page") page:Int, ):Response<SearchBooksResponse>
调用代码
fun facetLibrariesSpinnerItem(facetId:String?,item:String?,term: String){ viewModelScope.launch (Dispatchers.IO ){ val user = dataManager.getUser() val mapValue = mutableMapOf<String,String>() mapValue.put("f[0]", "$facetId:$item") try{ val response = librarySearch.librariesSearchBook(user.access_token,mapValue,term,searchPageIndex) if(response.isSuccessful){ print(response) } }catch (exception: Exception){ print(exception.message) } } }
问题描述:传入的QueryMap参数包含带空格的字符串(如"Name: Hashir Hamza"),会被自动转换为"Name:%20Hashir%20Hamza",需要将参数原样发送给API。
解决方案
方法1:改用@Query单独指定参数并关闭编码
将f[0]参数从QueryMap中移出,单独使用@Query注解并设置encoded = true,这样Retrofit会直接使用你传入的原始字符串,不会自动编码:
修改后的接口定义:
@GET("restful/api/search") suspend fun librariesSearchBook( @Header("Authorization") access_token: String, @Query("f[0]", encoded = true) facetValue: String?, @Query("term") term: String, @Query("page") page: Int, ): Response<SearchBooksResponse>
调用代码调整:
fun facetLibrariesSpinnerItem(facetId: String?, item: String?, term: String) { viewModelScope.launch(Dispatchers.IO) { val user = dataManager.getUser() val facetValue = if (facetId != null && item != null) "$facetId:$item" else null try { val response = librarySearch.librariesSearchBook( user.access_token, facetValue, term, searchPageIndex ) if (response.isSuccessful) { print(response) } } catch (exception: Exception) { print(exception.message) } } }
方法2:自定义OkHttpClient禁用URL编码(谨慎使用)
如果需要保留QueryMap的用法,可以配置OkHttpClient,让它不对Query参数进行编码。注意:这会影响所有请求的参数编码,可能导致其他参数不符合URL规范,仅在确认API接受原始空格的情况下使用:
val okHttpClient = OkHttpClient.Builder() .addInterceptor { chain -> val originalRequest = chain.request() val originalUrl = originalRequest.url // 手动构建URL,保留原始Query参数 val newUrl = originalUrl.newBuilder() .query(originalUrl.query()) // 直接使用原始Query字符串,不编码 .build() val newRequest = originalRequest.newBuilder() .url(newUrl) .build() chain.proceed(newRequest) } .build()
然后将这个OkHttpClient传入Retrofit构建器:
val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build()
注意事项
URL中直接包含空格不符合HTTP规范,大部分服务器会自动将空格解析为%20或+。如果你的API确实要求必须发送原始空格,才建议使用上述方法;否则优先确认API是否接受%20或+作为空格的替代方案。
内容的提问来源于stack exchange,提问作者Hashir Hamza
相关产品推荐
相关产品推荐

