Retrofit2 的baseUrl 真的必須以?/(斜線)?結(jié)尾嗎?

【Retrofit GitHub】: https://github.com/square/retrofit
版本:2.4.0

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

最近剛好想看看Retrofit源碼了,之前看過好多博文都提到注意Retrofit2 的baseUrl 必須以 /(斜線) 結(jié)束,不然會(huì)拋出一個(gè)IllegalArgumentException異常
個(gè)人感覺這段話說(shuō)的不嚴(yán)謹(jǐn),并不是所有的baseUrl不以 /(斜線) 結(jié)尾就會(huì)拋出一個(gè)IllegalArgumentException異常,這里就需要講述一下Url的格式了,往往一個(gè)Url格式為scheme://host[:port]/path[?query],

  • scheme協(xié)議,常用的協(xié)議是http、https
  • host 主機(jī)地址,可以是域名,也可以是IP地址
  • port 端口 http協(xié)議默認(rèn)端口是:80端口,如果不寫默認(rèn)就是:80端口,https默認(rèn)端口443端口
  • path 路徑 網(wǎng)絡(luò)資源在服務(wù)器中的指定路徑
  • query 查詢字符串 如果需要從服務(wù)器那里查詢內(nèi)容
public static final String API_URL = "https://api.github.com";
public interface GitHub {
    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(
        @Path("owner") String owner,
        @Path("repo") String repo);
  }

現(xiàn)在以https://api.github.com/repos/{owner}/{repo}/contributors這個(gè)接口為例,此處的

  • https為scheme,
  • api.github.com為host,此處端口沒寫(https默認(rèn)443),
  • repos/{owner}/{repo}/contributors為path,

關(guān)于Retrofit中的baseUrl并沒有強(qiáng)制怎么寫,我可以寫成https://api.github.com也可以寫成 https://api.github.com/repos/,區(qū)別在哪呢?下面聽我仔細(xì)說(shuō):

  1. https://api.github.com的格式可以看成scheme://host[:port](此種類型是不是以 /(斜線) 結(jié)尾都可以,均不會(huì)拋出IllegalArgumentException異常);
  2. https://api.github.com/repos/的格式可以看成scheme://host[:port]/path(此種類型必須以/(斜線) 結(jié)尾,否則會(huì)拋出IllegalArgumentException異常).

下面關(guān)于baseUrl的問題來(lái)看看Retrofit.java中的源碼:

public Builder baseUrl(String baseUrl) {
     checkNotNull(baseUrl, "baseUrl == null");
     HttpUrl httpUrl = HttpUrl.parse(baseUrl);
     if (httpUrl == null) {
       throw new IllegalArgumentException("Illegal URL: " + baseUrl);
     }
     return baseUrl(httpUrl);
 }
?
public Builder baseUrl(HttpUrl baseUrl) {
     checkNotNull(baseUrl, "baseUrl == null");
     List<String> pathSegments = baseUrl.pathSegments();
     if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
       throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
     }
     this.baseUrl = baseUrl;
     return this;
 }

可以看到第二個(gè)baseUrl方法中會(huì)在一定場(chǎng)景下拋出IllegalArgumentException異常,但是在第一個(gè)baseUrl方法中HttpUrl.parse(baseUrl)會(huì)對(duì)baseUrl做處理轉(zhuǎn)換成對(duì)應(yīng)的HttpUrl,區(qū)別就在這里了,對(duì)于場(chǎng)景1中https://api.github.com會(huì)自動(dòng)轉(zhuǎn)換成https://api.github.com/,如下圖:

場(chǎng)景1.png

而場(chǎng)景2中自然不會(huì)做處理,若場(chǎng)景2中寫成https://api.github.com/repos未以 /(斜線) 結(jié)尾,此時(shí)HttpUrl.parse(baseUrl)也不會(huì)對(duì)此做處理,那么就會(huì)拋出IllegalArgumentException異常。如下圖:

場(chǎng)景2.png

拋異常.png

注意:建議BaseUrl以/(斜線) 結(jié)尾。scheme://host[:port]/path類型的baseUrl必須以/(斜線) 結(jié)尾。

路徑整合規(guī)則:

BaseUrl Path形式 Path對(duì)應(yīng)的值 最后Url
http://host:port/a/b/ 絕對(duì)路徑 /apath http://host:port/apath
http://host:port/a/b/ 相對(duì)路徑 apath http://host:port/a/b/apath
http://host:port/a/b/ 完整路徑 http://host:port/aa/apath http://host:port/aa/apath
  • Path中提供的url是絕對(duì)路徑,即以 / 開頭,則請(qǐng)求的url為baseUrl的主機(jī)部分(或加上端口);
  • Path對(duì)應(yīng)的值Path中提供的url是相對(duì)路徑,即不以 / 開頭,則請(qǐng)求的url為baseUrl;
  • Path對(duì)應(yīng)的值Path中提供的url是完整路徑,則url將作為最終請(qǐng)求的url。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,973評(píng)論 19 139
  • # Python 資源大全中文版 我想很多程序員應(yīng)該記得 GitHub 上有一個(gè) Awesome - XXX 系列...
    aimaile閱讀 26,588評(píng)論 6 427
  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,568評(píng)論 2 45
  • 那是十幾年前的事了。舅舅家的孩子剛在太原參加工作。我也師范剛畢業(yè),暑假里到舅舅家玩。表哥順便請(qǐng)我到太原玩,我很高興...
    海魚緣閱讀 354評(píng)論 5 3
  • 1 那天,正當(dāng)深夜零時(shí),她忙完手中的工作,在睡夢(mèng)中幾近徘徊,意識(shí)飄忽。 所以當(dāng)電話的震動(dòng)與鈴聲響起,她也能迷迷糊糊...
    目覺閱讀 736評(píng)論 1 22