Retrofit2应对各类奇葩接口的方法

最近这一年半,实在是大开眼界了,面对各类奇葩的接口,在紧凑的开发周期下,没有时间细想如何去面对,好在最近稍微悠闲了,就把遇到的各类奇葩接口整理了一下,本身手写Spring去模拟这些接口,而后尝试用Retrofit一一破解,终于被我摸出了一些门道。java

Post请求上传Json

首先说明一点,用Json作先后端交互实际上是很好的作法,我我的也很推荐这样来玩。spring

遇到这种场景,咱们首先想到的就是百度,而后咱们会了解如下写法:json

方法1:后端

@Headers("Content-Type: application/json;charset=UTF-8", "Accept: application/json")
@POST(ServerAPI.JPUSH_UPLOAD_DEVICE_TOKEN_INFO)

fun uploaddevicetoken(@Body body: RequestBody): Single<LaiKangJunVO<Any>>


//--------------------------
val gson = Gson()
val jsonJpushStr = gson.toJson(jpushload)
val requstBody = RequestBody.create(MediaType.parse("application/json"), jsonJpushStr)
val disposable = accountService.uploaddevicetoken(requstBody)
.subscribeOn(Schedulers.io())

这种方式并无错,可是咱们忽略了一点,咱们添加了ConverterFactory。咱们都知道,若是添加ConverterFactory,就能够直接这样写:app

方法2:ide

@POST("test4")
fun test4(@Body test: Test):Single<Bean>

//----------------------
service.test4(Test("XXX", 11))
	.subscribeOn(Schedulers.io())
	.subscribe({
	val i = 0
	}, {
	val i = 0
	})

直接把对象当参数传入便可,是否是方便不少?ui

传递空Json

有个弟弟写过一个接口,让我传一个空的Json串,即“{}”,我先用上面的方法1来跑,无论怎么写retrofit都会报错,时间紧没办法,我跑去找弟弟吵了一架,让人家改了。可是后来反思,当哥的应该尽可能兼容弟弟,这个问题该怎么解决呢,之后再遇到这问题该怎么处理,直到我用上面的方法2传递了一个空的对象,终于解决了:url

data class TestBean()

@POST("test4")
fun test(@Body bean: TestBean):Single<Bean>

//----------------------
service.test(TestBean())
	.subscribeOn(Schedulers.io())
	.subscribe({
	val i = 0
	}, {
	val i = 0
	})

接口只返回ResponseHeader

事情的原由是,在作「注销」接口时,后端弟弟在spring拦截器里面去拦截参数,不知足的话他不能返回responseBody,只能返回一个responseHeder,可是因为咱们用了ConverterFactory,retrofit会自动把responseBody反序列化成对象,但此时的responseBody是个空串,因此在解析的时候就会报解析错误end of .....code

应对这种场景,咱们能够直接使用retrofit内部的okhttp来实现:对象

private fun ok() {
	val req = Request.Builder()
	.url(url + "test")
	.build()

	val moshi = Moshi.Builder().build()
	val call = client.newCall(req)
	call.enqueue(object : Callback {
	override fun onResponse(call: Call, response: Response) {
	val head = response.headers()
	val head1 = response.header("Date")
	val test = TestJsonAdapter(moshi).fromJson(response.body()?.source())
	val i = 0

	}

	override fun onFailure(call: Call, e: IOException) {
	val i = 0
	}
	})
}

可是这样以来就形成了咱们的代码的不统一。在我百般尝试和各类百度后,终于找到一篇帖子,因而有了如下的解决方案:

@POST("test4")
    fun test4(@Body test: Test):Single<retrofit2.Response<Boolean>>
	
//---------------------------------

private fun retrofit4():Disposable {
	return service.test4(Test("XXX", 11))
	.subscribeOn(Schedulers.io())
	.subscribe({
		val i = 0
		val token = it.headers()["token"]
	}, {
		val i = 0
	})
}

登陆后全局加参数/动态切换全局参数

咱们都知道retrofit能够全局在请求头中加参数:

val client = OkHttpClient.Builder()
client.addInterceptor {
	val oriReq = it.request()
	val req = oriReq.newBuilder()
	.header("token", token.toString())
	.method(oriReq.method(), oriReq.body())
	.build()
	it.proceed(req)
}
retrofit = Retrofit.Builder()
	.baseUrl(url)
	.client(client.build())
	.addConverterFactory(MoshiConverterFactory.create())
	.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
	.build()
service = retrofit.create(Service::class.java)
相关文章
相关标签/搜索