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

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

Post请求上传Json

首先说明一点,用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>


//--------------------------
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,就可以直接这样写:

方法2:

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

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

直接把对象当参数传入即可,是不是方便很多?

传递空Json

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

data class TestBean()

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

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

接口只返回ResponseHeader

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

应对这种场景,我们可以直接使用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>
	
//---------------------------------

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)

转载于:https://my.oschina.net/JiangTun/blog/3076176

你可能感兴趣的:(Retrofit2应对各种奇葩接口的方法)