Android - 改造 - 基本网址中缺少查询参数
Posted
技术标签:
【中文标题】Android - 改造 - 基本网址中缺少查询参数【英文标题】:Android - retrofit - Query parameters missing from Base Url 【发布时间】:2019-08-10 22:08:44 【问题描述】:我正在使用 Dagger2 + Retrofit + Rxandroid + OkHttp3 + 新架构组件开发一个 android 应用程序。 最小 SDK = 16.
问题:在 API 16 上运行应用程序时,Url 生成不正确。 Url 缺少我通过 Retrofit 传递的 @QueryMap 参数。当我在 api 级别 21+ 上测试应用程序时,同样可以正常工作。
正确的网址 - 在 api 21+ - "http://api.apixu.com/v1/forecast.json?q=IDR&days=10&key=apikey"
在 api 16/19 上生成的网址 - “http://api.apixu.com/v1/forecast.json”
改造界面 -
@GET("forecast.json")
fun fetchWeatherDetails(
@QueryMap hashMap: @NotNull HashMap<String, String>
): @NotNull Observable<ApiResponse>
改造生成器 -
val httpClient = getOkHttpClient()
return Retrofit.Builder()
.baseUrl(apiBaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build()
OkHttpClient -
val builder = OkHttpClient.Builder()
builder
.cache(cache)
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.followRedirects(true)
.followSslRedirects(true)
val httpLoggingInterceptor = HttpLoggingInterceptor()
if (BuildConfig.DEBUG)
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
else
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.NONE
builder.addInterceptor(HeaderInterceptor())
.addInterceptor(httpLoggingInterceptor)
return builder.build()
自从我陷入这个问题以来已经超过 2 天了。任何帮助将不胜感激。
更新: API 查询代码在 API 21+ 上运行良好。
在 API-16 和 API-19 上失败。
【问题讨论】:
您的问题很奇怪,只能说一个建议,尝试使用查询而不是 QueryMap。可以解决您的问题。 试过了。使用@Query - 同样的问题。当传递整个网址时 - 它工作正常。我认为这个问题很简单——在 api23+ 上解析 url,但在 api 16 上没有解析。我想知道它是否与 api 级别 16 的向后兼容性有关。 【参考方案1】:很明显,您的 URL 没有编码,为此,您需要确保在所有平台上使用 @QueryMap(encoded = true)
对其进行编码。
如果不成功,恐怕您需要使用自定义 interceptor 手动执行此操作,以对 ?
等等于 %3F
的字符进行编码,例如:
@Override
Response intercept(Interceptor.Chain chain) throws IOException
Request request = chain.request()
def string = request.url().toString()
string = string.replace("%26", "&")
string = string.replace("%3D", "=")
string = string.replace("%3F", "?")
Request newRequest = new Request.Builder()
.url(string)
.build()
return chain.proceed(newRequest)
参考资料:
Question mark in the middle of a url variable? https://github.com/square/retrofit/issues/1199【讨论】:
那么为什么它在 api level 23+ 而不是在 api level 16 中工作?这是主要问题。改造正在正确查询 url 并在 api23+ 中按预期显示结果。但是当我在 api16 -> 上运行它时会出错。在日志中我可以看到被查询的 url 解析不正确。 @PranavBhoraskar 我相信支持下降 16+ 即:注释或一些外部 API,由于 API 29 的存在很难修复。【参考方案2】:伙计,请阅读 OkHttp 要求部分:https://github.com/square/okhttp#requirements 它确实提到只有 3.12.x 分支支持 Android 2.3+(API 级别 9+)和 Java 7+。对设备
【讨论】:
【参考方案3】:终于!!我解决了这个问题。 解决方案 - 诀窍是使用拦截器。通过检查正确的 SDK VERSION 和拦截器,我终于开始运行了。
internal class HeaderInterceptor : Interceptor
override fun intercept(chain: Interceptor.Chain): Response
var request = chain.request()
val url = request.url().newBuilder()
.addQueryParameter("key", API_KEY)
.addQueryParameter("q", QUERY_PARAMETER)
.addQueryParameter("days", DAYS)
.build()
request = request.newBuilder().url(url).build()
return chain.proceed(request)
OkHttpClient 需要 SDK_VERSION 检查 -
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
builder.addInterceptor(HeaderInterceptor())
所以我在这里抓住的是 - @QueryMap(在改造中)很好地构建了 SDK-21+ 的 url。对于 SDKs
感谢大家对此事的帮助。我相信有人会觉得这很有帮助!
【讨论】:
以上是关于Android - 改造 - 基本网址中缺少查询参数的主要内容,如果未能解决你的问题,请参考以下文章