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 - 改造 - 基本网址中缺少查询参数的主要内容,如果未能解决你的问题,请参考以下文章

如何将int值附加到android中改造的GET url

如何使用改造 2 在 Android 中获取 Json,如下面的代码所示?

改造查询参数采用 & 和 ?一起

在 Android 中使用改造

改造:@GET 命令中的多个查询参数?

如何把Ubuntu 18.04改造成Windows主题界面