android - 带有空响应正文的 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
消息 :Throwable
onFailure
com.google.gson.stream.MalformedJsonException:
Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
有没有人知道可能导致这种情况的原因?
解决方案
终于弄明白了,希望这对以后的人有帮助...
来自 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()
}
推荐阅读
- c# - VSTO Excel 加载项在用于签名的证书到期日期后不起作用
- angular - 命名路由器出口导致 Angular 11 应用程序中出现“无法匹配任何路由”错误
- java - 处理未检测到死苍蝇
- python - 我在使用 word2vec 时遇到了问题。可能是版本问题,不知道怎么解决?
- javascript - 使用正则表达式获取一个单词后的美元金额
- java - 我的应用程序正在将 Db 实体序列化到 Web 服务层。如何全部转为 DTO?
- flutter - 出现错误:框
' 不能分配给参数类型 'ValueListenable ' - javascript - 根据嵌套数组值更改值
- amazon-web-services - 从 GCP 或 Azure 访问 AWS 资源 (aws xray)
- reactjs - 渲染数组的每个对象,这是反应中键的值