美文网首页Android开发经验谈Android开发Android知识
Retrofit2 的baseUrl 真的必须以 /(斜线) 结

Retrofit2 的baseUrl 真的必须以 /(斜线) 结

作者: 闲庭 | 来源:发表于2017-10-25 22:24 被阅读1010次

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

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

    最近刚好想看看Retrofit源码了,之前看过好多博文都提到注意Retrofit2 的baseUrl 必须以 /(斜线) 结束,不然会抛出一个IllegalArgumentException异常
    个人感觉这段话说的不严谨,并不是所有的baseUrl不以 /(斜线) 结尾就会抛出一个IllegalArgumentException异常,这里就需要讲述一下Url的格式了,往往一个Url格式为scheme://host[:port]/path[?query],

    • scheme协议,常用的协议是http、https
    • host 主机地址,可以是域名,也可以是IP地址
    • port 端口 http协议默认端口是:80端口,如果不写默认就是:80端口,https默认端口443端口
    • path 路径 网络资源在服务器中的指定路径
    • query 查询字符串 如果需要从服务器那里查询内容
    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);
      }
    

    现在以https://api.github.com/repos/{owner}/{repo}/contributors这个接口为例,此处的

    • https为scheme,
    • api.github.com为host,此处端口没写(https默认443),
    • repos/{owner}/{repo}/contributors为path,

    关于Retrofit中的baseUrl并没有强制怎么写,我可以写成https://api.github.com也可以写成 https://api.github.com/repos/,区别在哪呢?下面听我仔细说:

    1. https://api.github.com的格式可以看成scheme://host[:port](此种类型是不是以 /(斜线) 结尾都可以,均不会抛出IllegalArgumentException异常);
    2. https://api.github.com/repos/的格式可以看成scheme://host[:port]/path(此种类型必须以/(斜线) 结尾,否则会抛出IllegalArgumentException异常).

    下面关于baseUrl的问题来看看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;
     }
    

    可以看到第二个baseUrl方法中会在一定场景下抛出IllegalArgumentException异常,但是在第一个baseUrl方法中HttpUrl.parse(baseUrl)会对baseUrl做处理转换成对应的HttpUrl,区别就在这里了,对于场景1中https://api.github.com会自动转换成https://api.github.com/,如下图:

    场景1.png

    而场景2中自然不会做处理,若场景2中写成https://api.github.com/repos未以 /(斜线) 结尾,此时HttpUrl.parse(baseUrl)也不会对此做处理,那么就会抛出IllegalArgumentException异常。如下图:

    场景2.png 抛异常.png

    注意:建议BaseUrl以/(斜线) 结尾。scheme://host[:port]/path类型的baseUrl必须以/(斜线) 结尾。

    路径整合规则:

    BaseUrl Path形式 Path对应的值 最后Url
    http://host:port/a/b/ 绝对路径 /apath http://host:port/apath
    http://host:port/a/b/ 相对路径 apath http://host:port/a/b/apath
    http://host:port/a/b/ 完整路径 http://host:port/aa/apath http://host:port/aa/apath
    • Path中提供的url是绝对路径,即以 / 开头,则请求的url为baseUrl的主机部分(或加上端口);
    • Path对应的值Path中提供的url是相对路径,即不以 / 开头,则请求的url为baseUrl;
    • Path对应的值Path中提供的url是完整路径,则url将作为最终请求的url。

    相关文章

      网友评论

        本文标题:Retrofit2 的baseUrl 真的必须以 /(斜线) 结

        本文链接:https://www.haomeiwen.com/subject/ifucpxtx.html