最近這一年半,實在是大開眼界了,面對各類奇葩的接口,在緊湊的開發週期下,沒有時間細想如何去面對,好在最近稍微悠閒了,就把遇到的各類奇葩接口整理了一下,本身手寫Spring去模擬這些接口,而後嘗試用Retrofit一一破解,終於被我摸出了一些門道。java
首先說明一點,用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串,即「{}」,我先用上面的方法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 })
事情的原由是,在作「註銷」接口時,後端弟弟在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)