在之前的《Retrofit之初體驗》中,我們初步了解了如何使用Retrofit,沒有閱讀過的同學,建議先閱讀下。接下來,我們開始討論Retrofit的各個細節,本文介紹的是如何定義Retrofit的請求url。
base url與端點url的連接
從上文我們知道,Retrofit在Java接口方法上使用注解來描述API端點及請求的處理:
- 定義HTTP請求方法,GET、POST、PUT、DELETE等等,Retrofit中都有相對應的注解。
- 在注解上添加相對資源端點url。
于是就會有像這樣的一個接口:
public interface WeiboService {
@GET("statuses/public_timeline.json")
Call<Object> timelineForPublic();
}
Retrofit類定義了base url,而這里通過GET注解定義的資源url會與base url連接起來作為最終的請求url。
我們定義的base url為:
Retrofit.Builder().baseUrl("https://api.weibo.com/2/");
得到的最終的請求url為:
https://api.weibo.com/2/statuses/public_timeline.json
當然,這個最終請求url是正確的,那么如果base url中的末尾不帶"/",而在端點url的前段帶"/",是否也一樣可以呢?答案是不可以,app直接崩潰了,拋出了ExceptionInInitializerError異常,因為Retrofit要求base url必須以"/"結尾。
好的,base url是不能改了,那如果只在端點url的前面加"/"會如何呢?
此時得到的最終請求url為:
https://api.weibo.com/statuses/public_timeline.json
這又是為什么呢?
首先,明確一個概念,當端點url以"/"開頭時代表絕對路徑后綴路徑,而base url的中的"2"則為路徑參數。當端點url是絕對路徑時,在base url中包含的路徑參數會被忽略,于是就變成了最終的"https://api.weibo.com/statuses/public_timeline.json"。
base url的應用
在處理API時,通常它們都有共同的基本地址,也就是Retrofit中的base url。有時候,因為服務器的升級,可能會發生改變,例如微博的從api從版本2升級到版本3,那么base url就會變成"https://api.weibo.com/3/",而我們只需要在定義base url的地方更改即可,這樣每個端點的最終請求url也都會隨之改變。亦或者,可能有測試服務器、預發服務器以及正式服務器,API的端點url不會改變,改變的都只會是base url。
端點url的應用
在上面談base url與端點url連接時了解到,當base url以"/"開頭時,會忽略base url中的路徑參數。好了,現在假如有這樣一種情況,微博的大部分api還是版本2,但是獲取廣場微博的api從版本2升級到版本3,也就是請求url應該為:
https://api.weibo.com/3/statuses/public_timeline.json
因此,我們可以在定義API端點時,將端點url設置為"/3/statuses/public_timeline.json",這樣就可以使得獲取廣場微博調用版本3的API,而其他的還是使用版本2的API。
動態url的應用
使用base url和端點url可以應對大多數API,但是應用中總會出現另類的API。在我的示例中,現在要獲取天氣,當然我只能找到一個免費的api了,鏈接是:http://apistore.baidu.com/apiworks/servicedetail/112.html,可以看到請求的url是"http://apis.baidu.com/apistore/weatherservice/weather",此時base url就完全不可用了,這時候就到了動態url出場的時間了。
定義動態url只需要添加一個字符串參數用來表示url,并使用@Url注解:
public interface WeatherService {
@Headers("apikey:b86c2269fe6588bbe3b41924bb2f2da2")
@GET
Call<WeatherWrapper> weather(@Url String url, @Query("cityname") String cityName);
}
代碼中的@Headers是用來添加請求頭的,這塊暫不用管,后續會有文章進行介紹。好了,關注我們的動態url,可以發現現在@GET注解后面沒有了端點url,并使用了@Url來定義請求url。
上面我們了解了base url和端點url的連接,那Retrofit又是如何處理base url和動態url的呢?
分三種情況(base url為"https://api.weibo.com/2/"):
- 動態url包含完整的scheme和host,直接使用動態url作為最終的請求url。例如動態url為"http://apis.baidu.com/apistore/weatherservice/weather",那么最終的請求url也為"http://apis.baidu.com/apistore/weatherservice/weather"。
- 動態url包含該host,則使用base url的scheme連接動態url作為最終的請求url。例如動態url為"//apis.baidu.com/apistore/weatherservice/weather",那么最終的請求url為"https://apis.baidu.com/apistore/weatherservice/weather"。
- 動態url不包含scheme和host,則將base url與動態url連接起來作為最終的請求url,與在@GET后定義端點url一致。例如動態url為"/apistore/weatherservice/weather",那么最終的請求url為"https://api.weibo.com/apistore/weatherservice/weather"。
根據使用場景,靈活使用url的定義方式,就可以處理各種url了。如果你對retrofit感興趣,同時你也覺得我的文章可以給你帶來那么一丟丟的幫助,敬請關注,后續會繼續介紹Retrofit的相關使用。
源碼地址:
https://github.com/FILWAndroid/DevJourney
關于源碼:
- 不只是本文涉及的代碼,會包含很多知識點的代碼,應該都會在我的簡書中進行介紹。
- 有可能代碼與本文中所貼出來的有差異,但應該都是我覺得更好的方式吧。
- 新浪微博相關的代碼運行顯示不出來結果,感興趣的可以參考新浪微博SDK,配置工程。
- 歡迎大家對我進行批評教育。