无法使用 Retrofit 2.6.1 成功发送 POST 请求 - JSON 转换器存在问题
Unable to successfully send a POST request using Retrofit 2.6.1 - Problems with JSON coverter
我正在使用带有暂停协程的新 Retrofit2,并且使用 GET 请求一切正常。
但我现在必须执行一个 POST 请求,但无法让它工作
我有一个如下所示的 CURL 示例:
curl -X POST -H "Content-Type: application/json;charsets: utf-8" -d '{"tx_guapptokenlist_tokenitem":{"tokenchar":"my-token-string","platform":"android"}}' https://www.example-url.com/tokens?type=56427890283537921
这很好用,并且 return 的响应是:{"errors":false,"success":true}%
现在我的 Api class 中的请求如下所示:
@Headers( "Content-Type: application/json" )
@POST("/tokens?type=56427890283537921")
suspend fun sendFirebaseToken(@Body tokenRequest: RequestBody) : Call<TokenResponse>
这是我的 TokenResponse class:
@JsonClass(generateAdapter = true)
data class TokenResponse(
@Json(name="errors")
val errors: Boolean,
@Json(name="success")
val success: Boolean)
和 Api客户端 class 我正在使用:
object ApiClient {
private const val BASE_URL = "https://myExampleUrl.com"
private var retrofit: Retrofit? = null
var moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val client: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder().baseUrl(
BASE_URL
).client(getOkHttpClient())
.addConverterFactory(MoshiConverterFactory.create())
.build()
}
return retrofit
}
fun getOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(getLoggingInterceptor())
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS).writeTimeout(90, TimeUnit.SECONDS).build()
}
private fun getLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().setLevel(
if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.HEADERS
else HttpLoggingInterceptor.Level.NONE
)
}
}
我注意到的第一件奇怪的事情:即使有 @POST
注释,如果我的 suspend fun
没有 return 类型,我不会收到任何错误,但是 okhttp 总是会发送一个 GET请求(至少端点总是收到 GET)。不确定是否应该像那样?
无论如何:我需要 return 值,所以我 returning Call<TokenResponse>
。
这引出了我无法解决的主要问题:如果现在我执行我的代码,它会崩溃并显示以下日志:
java.lang.IllegalArgumentException: Unable to create converter for retrofit2.Call<myapp.communication.TokenResponse>
for method TokenApi.sendToken
at retrofit2.Utils.methodError(Utils.java:52)
为了尝试解决这个问题,我使用了 moshi-kotlin-codegen 来生成正确的适配器(因此在数据 class 中有注释),但无济于事。 class 已生成,但未使用。我试过像这样 var moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
将带有 JsonAdapterFactory 的 Moshi 传递给我的 ConverterFactory,但这也不起作用。
尝试将生成的适配器手动添加到 moshi,但这也没有用。
我也在我的请求中尝试了 returning 不同的类型。 Retrofit 文档指出,如果没有转换器,只能 return a ResponseBody
,但结果相同:Retrofit 抱怨它没有转换器。 returning Call<Void>
也一样
我觉得我在这里遗漏了什么?谁能帮忙?很高兴提供更多详细信息,请提出要求。
认为注释应该是:
@JsonClass(generateAdapter = true)
data class TokenResponse(
@field:Json(name = "errors") val errors: Integer,
@field:Json(name = "success") val success: Boolean
)
并尝试删除一次 suspend
关键字,这可能会与 generateAdapter = true
冲突。
您的请求函数应如下所示。
@Headers( "Content-Type: application/json" )
@POST("/tokens?type=56427890283537921")
suspend fun sendFirebaseToken(@Body tokenRequest: RequestBody): TokenResponse
您没有使用 Call<...>
,因为您已将其标记为暂停。
我现在已经开始工作了,这是我学到的:
首先:@Dominic Fischer 是对的,Call
是错误的,并且在所有设置正确的情况下,根本不需要包装结果对象(我注意到@Headers
注释的方式看起来不是必需的,Retrofit 似乎只是处理它)。
第二个也是最大的问题是我的ApiClient
class中的client
对象没有被正确使用。查看新版本:
fun getRetrofitService(): ApiService {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(getOkHttpClient())
.addConverterFactory(MoshiConverterFactory.create())
.build().create(ApiService::class.java)
}
看到现在添加了 'create()' 步骤,在我在此 class 之外处理之前。在那里,我使用我的 Retrofit
对象来创建服务,就像这里一样,但我不小心传递了 ApiClient::class.java
。有趣的是编译和运行都很好,但当然这一定是在某个地方搞砸了——它无法正确构建 JSON 适配器。
因此我把这一步拉进了我的 ApiClient
以防止将来发生此类事故。
如果有人对这个问题提出建议+对未来的读者更有用,请告诉我!
我正在使用带有暂停协程的新 Retrofit2,并且使用 GET 请求一切正常。
但我现在必须执行一个 POST 请求,但无法让它工作
我有一个如下所示的 CURL 示例:
curl -X POST -H "Content-Type: application/json;charsets: utf-8" -d '{"tx_guapptokenlist_tokenitem":{"tokenchar":"my-token-string","platform":"android"}}' https://www.example-url.com/tokens?type=56427890283537921
这很好用,并且 return 的响应是:{"errors":false,"success":true}%
现在我的 Api class 中的请求如下所示:
@Headers( "Content-Type: application/json" )
@POST("/tokens?type=56427890283537921")
suspend fun sendFirebaseToken(@Body tokenRequest: RequestBody) : Call<TokenResponse>
这是我的 TokenResponse class:
@JsonClass(generateAdapter = true)
data class TokenResponse(
@Json(name="errors")
val errors: Boolean,
@Json(name="success")
val success: Boolean)
和 Api客户端 class 我正在使用:
object ApiClient {
private const val BASE_URL = "https://myExampleUrl.com"
private var retrofit: Retrofit? = null
var moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
val client: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder().baseUrl(
BASE_URL
).client(getOkHttpClient())
.addConverterFactory(MoshiConverterFactory.create())
.build()
}
return retrofit
}
fun getOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(getLoggingInterceptor())
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS).writeTimeout(90, TimeUnit.SECONDS).build()
}
private fun getLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().setLevel(
if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.HEADERS
else HttpLoggingInterceptor.Level.NONE
)
}
}
我注意到的第一件奇怪的事情:即使有 @POST
注释,如果我的 suspend fun
没有 return 类型,我不会收到任何错误,但是 okhttp 总是会发送一个 GET请求(至少端点总是收到 GET)。不确定是否应该像那样?
无论如何:我需要 return 值,所以我 returning Call<TokenResponse>
。
这引出了我无法解决的主要问题:如果现在我执行我的代码,它会崩溃并显示以下日志:
java.lang.IllegalArgumentException: Unable to create converter for retrofit2.Call<myapp.communication.TokenResponse>
for method TokenApi.sendToken
at retrofit2.Utils.methodError(Utils.java:52)
为了尝试解决这个问题,我使用了 moshi-kotlin-codegen 来生成正确的适配器(因此在数据 class 中有注释),但无济于事。 class 已生成,但未使用。我试过像这样 var moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
将带有 JsonAdapterFactory 的 Moshi 传递给我的 ConverterFactory,但这也不起作用。
尝试将生成的适配器手动添加到 moshi,但这也没有用。
我也在我的请求中尝试了 returning 不同的类型。 Retrofit 文档指出,如果没有转换器,只能 return a ResponseBody
,但结果相同:Retrofit 抱怨它没有转换器。 returning Call<Void>
我觉得我在这里遗漏了什么?谁能帮忙?很高兴提供更多详细信息,请提出要求。
认为注释应该是:
@JsonClass(generateAdapter = true)
data class TokenResponse(
@field:Json(name = "errors") val errors: Integer,
@field:Json(name = "success") val success: Boolean
)
并尝试删除一次 suspend
关键字,这可能会与 generateAdapter = true
冲突。
您的请求函数应如下所示。
@Headers( "Content-Type: application/json" )
@POST("/tokens?type=56427890283537921")
suspend fun sendFirebaseToken(@Body tokenRequest: RequestBody): TokenResponse
您没有使用 Call<...>
,因为您已将其标记为暂停。
我现在已经开始工作了,这是我学到的:
首先:@Dominic Fischer Call
是错误的,并且在所有设置正确的情况下,根本不需要包装结果对象(我注意到@Headers
注释的方式看起来不是必需的,Retrofit 似乎只是处理它)。
第二个也是最大的问题是我的ApiClient
class中的client
对象没有被正确使用。查看新版本:
fun getRetrofitService(): ApiService {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(getOkHttpClient())
.addConverterFactory(MoshiConverterFactory.create())
.build().create(ApiService::class.java)
}
看到现在添加了 'create()' 步骤,在我在此 class 之外处理之前。在那里,我使用我的 Retrofit
对象来创建服务,就像这里一样,但我不小心传递了 ApiClient::class.java
。有趣的是编译和运行都很好,但当然这一定是在某个地方搞砸了——它无法正确构建 JSON 适配器。
因此我把这一步拉进了我的 ApiClient
以防止将来发生此类事故。
如果有人对这个问题提出建议+对未来的读者更有用,请告诉我!