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<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,就可以直接這樣寫:
方法2:
@POST("test4")
fun test4(@Body test: Test):Single<Bean>
//----------------------
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<Bean> //---------------------- 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<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::