首页 > 解决方案 > 带有空响应正文的 Twitter oauth/request_token 200 代码

问题描述

我正在按照以下方式实施 Twitter OAuth 流程:

https://developer.twitter.com/en/docs/authentication/guides/log-in-with-twitter

我收到了第一步 (oauth/request_token) 的响应,其中包含 200 个代码,但响应正文完全为空。

我正在使用 Retrofit 调用 API,并连接了一个拦截器 OkHttpClient 来调试响应,如下所示:

val client = OkHttpClient.Builder().also { builder ->
    builder.addInterceptor { chain ->
        val request = chain.request()
        val response = chain.proceed(request)
        response
    }
}.build()

然后像这样设置改造:

Retrofit.Builder()
                .baseUrl(TWITTER_AUTH_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build()
                .create(TwitterAuthRetrofit::class.java)
                .getRequestToken(
                       authorizationHeaders
                ).enqueue(object : Callback<TwitterRequestToken> {
                    override fun onResponse(call: Call<TwitterRequestToken>, response: Response<TwitterRequestToken>) {
                        onSuccess(response.body())
                    }

                    override fun onFailure(call: Call<TwitterRequestToken>, t: Throwable) {
                        onFailure()
                    }
                })

当我在拦截器中调试时,我可以看到响应成功(200)但响应正文为空,我认为这导致我的 Gson 反序列化失败。

response.body.contentLength()在拦截器中调用的结果是-1。

在拦截器中调用的结果response.code是 200。

这是我试图将响应主体反序列化为的模型:

data class TwitterRequestToken(
        @SerializedName(value = "oauth_token")
        val token: String,
        @SerializedName(value = "oauth_token_secret")
        val tokenSecret: String,
        @SerializedName(value = "oauth_callback_confirmed")
        val callbackConfirmed: Boolean
)

请注意,我@SerializedName用于为响应主体提供键,而我的属性名称对于我们的应用程序是任意的(我们使用驼峰式大小写)。我GsonConverterFactory使用构建器向 Retrofit 实例添加了一个,并且之前对许多其他请求以相同的方式完成了此操作,没有任何问题。

这是我从 API 获得的响应,我正在通过上面的拦截器中的调试来查看它:

Response{protocol=h2, code=200, message=, url=https://api.twitter.com/oauth/request_token}

这是我在Retrofit 的回调中收到的cause消息 :ThrowableonFailure

com.google.gson.stream.MalformedJsonException: 
Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $

有没有人知道可能导致这种情况的原因?

标签: androidkotlintwittergsonretrofit

解决方案


终于弄明白了,希望这对以后的人有帮助...

来自 Twitter API 的 oauth/request_token 的响应正文未编码为 JSON;您将需要从响应缓冲区中读取它。具体来说,当使用 Retrofit 实现 API 时,您将希望您的 Retrofit 接口返回ResponseBody(而不是您的自定义类),从 Retrofit 构建器中删除 GSON,并在onResponseCallback从 Retrofit 中编写以下代码以将缓冲区读取为字符串,然后拆分字符串&以获取每个键 val 对,然后您可以拆分其中的每一个=并确保在构建模型之前拥有所有 3 个值:

override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
                        response.body()?.also { body ->
                            body.source().readString(Charsets.UTF_8).split('&').map { param ->
                                param.split('=').let { keyVal ->
                                    keyVal[0] to keyVal[1]
                                }
                            }.toMap().let { paramMap ->
                                val oauthToken = paramMap["oauth_token"]
                                val oauthTokenSecret = paramMap["oauth_token_secret"]
                                val oauthCallbackConfirmed = paramMap["oauth_callback_confirmed"]?.toBoolean()
                                if (oauthToken == null || oauthTokenSecret == null || oauthCallbackConfirmed == null) {
                                    onFailure()
                                } else {
                                    onSuccess(
                                            TwitterRequestToken(
                                                    oauthToken,
                                                    oauthTokenSecret,
                                                    oauthCallbackConfirmed
                                            )
                                    )
                                }
                            }
                        } ?: onFailure()
                    }

推荐阅读