【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ō):
-
https://api.github.com
的格式可以看成scheme://host[:port]
(此種類型是不是以 /(斜線) 結(jié)尾都可以,均不會(huì)拋出IllegalArgumentException
異常); -
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)景2中自然不會(huì)做處理,若場(chǎng)景2中寫成https://api.github.com/repos
未以 /(斜線) 結(jié)尾,此時(shí)HttpUrl.parse(baseUrl)
也不會(huì)對(duì)此做處理,那么就會(huì)拋出IllegalArgumentException
異常。如下圖:
注意:建議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。