zoukankan      html  css  js  c++  java
  • [转载]URL 源码分析

    URI 引用包括最多三个部分:模式、模式特定部分和片段标识符。一般为:
    模式:模式特定部分:片段
    如果省略模式,这个URI引用则是相对的。如果省略片段标识符,这个URI引用就是一个纯URI。

    URI是对URL的抽象,不仅包括统一资源定位符URL,还包括统一资源名URN。实际上使用的URI大多都是URL。在java中,URI使用java.net.URI类表示,URI类只能标识资源,和解析URI,而不能获取URI所标识的资源(URN是无法定位到资源的)。

    构造

    public URI(String str) throws URISyntaxException {
        new Parser(str).parse(false);
    }
    
    public URI(String scheme, String host, String path, String fragment)
        throws URISyntaxException{
        this(scheme, null, host, -1, path, null, fragment);
    }
    
    public URI(String scheme,
               String authority,
               String path, String query, String fragment)
        throws URISyntaxException{
    ....
    }
    
    public URI(String scheme,
               String userInfo, String host, int port,
               String path, String query, String fragment)
         throws URISyntaxException{
    ...
    }
    
    public URI(String scheme, String ssp, String fragment) throws URISyntaxException {
        new Parser(toString(scheme, ssp, null, null, null, -1, null, null, fragment)).parse(false);
    }
    
    

    URI类提供了5中构造方法

    1. 根据提供的一个uri字符串构造一个URI对象。
    2. 主要针对层次的URI。通过 模式、服务器地址、文件路径、片段标识构造URI。
    3. 主要针对层次的URI。通过 模式、授权机构、文件路径、查询条件、片段标识构造URI。
    4. 主要针对层次的URI。通过 模式、用户信息、服务器地址、端口、文件路径、查询条件、片段标识构造URI。
    5. 主要针对非层次URI。通过 模式、模式特定部分和片段标识创建URI。

    create方法

    public static URI create(String str) {
        try {
            return new URI(str);
        } catch (URISyntaxException x) {
            throw new IllegalArgumentException(x.getMessage(), x);
        }
    }
    

    如果可以确认URI的格式正确,可使用create的工厂方法创建URI。因为该方法不会抛出URISyntaxException异常。

    是否透明URL

    URI通常情况下都是层次(带“/”)的,但是也有不透明(没有“/”)的,层次的URI包含模式,主机,站点等各个部分,当然可能某些部分不包含,但是不透明的URI只包含三个部分,Scheme,Scheme-specific-part,Fragment.
    如:mailto:jijianshuai@infcn.com.cn

    public boolean isOpaque() {
        return path == null;
    }
    

    判断path是否为空,如果为空则是不透明的,说明URI中没有“/”。

     
    Paste_Image.png

    在URI构造器中解析URI,代码:new Parser(str).parse(false);

    判断URI中是否存在“/”符号,如果存在就是有层次结构的URI。
    如果存在“/”,则调用parseAuthority方法进行解析path。

    URI获取各部分信息

    1. 获得模式
      public String getScheme();
    2. 获得模式特定部分
      public String getSchemeSpecificPart();
      public String getRawSchemeSpecificPart();
    3. 获得片段
      public String getFragment();
      public String getRawFragment();
    4. 获得授权机构
      public String getAuthority();
      public String getRawAuthority()
      授权机构包括:用户信息、服务器地址(域名或ip)、端口
      user:password@localhost:80
    5. 获取片段标识
      public String getFragment()
      public String getRawFragment()
    6. 获取服务器地址(域名或ip)
      public String getHost()
    7. 获取路径
      public String getPath()
      public String getRawPath()
      路径包括(目录结构和文件部分)。如:/dir/index.html
    8. 获取端口
      public int getPort()
      如果没有端口则返回-1;
    9. 获取URI的查询字符串
      public String getQuery()
      public String getRawQuery()
    10. 获取用户信息
      public String getUserInfo()
      public String getRawUserInfo()

    如果URI是非透明只能获取到1~3个信息。
    如果URI是层次结构则能获取所有信息。

    方法中带Raw的,是获取编码后的URI部分信息。非ascii的字符需要进行编码,不带Raw的方法是解码后的信息。

    getScheme、getHost、getPort这三个方法没有Raw方法,是因为这三部分不会出现非ascii的字符。

    resolve 方法

    resolve方法可以将相对URI转换成绝对URI。示例如下:

    URI a = URI.create("http://localhost:8080/index.html");
    URI b = URI.create("user/userInfo.html");
    URI c = a.resolve(b);
    System.out.println(c);
    

    根据a获取b的绝对路径

    打印结果为:http://localhost:8080/user/userInfo.html

    源码如下
    public URI resolve(URI uri) {
        return resolve(this, uri);
    }
    
    private static URI resolve(URI base, URI child) {
        // check if child if opaque first so that NPE is thrown
        // if child is null.
        if (child.isOpaque() || base.isOpaque())
            return child;
    
        // 5.2 (2): Reference to current document (lone fragment)
        if ((child.scheme == null) && (child.authority == null)
            && child.path.equals("") && (child.fragment != null)
            && (child.query == null)) {
            if ((base.fragment != null) && child.fragment.equals(base.fragment)) {
                return base;
            }
            URI ru = new URI();
            ru.scheme = base.scheme;
            ru.authority = base.authority;
            ru.userInfo = base.userInfo;
            ru.host = base.host;
            ru.port = base.port;
            ru.path = base.path;
            ru.fragment = child.fragment;
            ru.query = base.query;
            return ru;
        }
    
        // 5.2 (3): Child is absolute
        if (child.scheme != null)
            return child;
        URI ru = new URI();             // Resolved URI
        ru.scheme = base.scheme;
        ru.query = child.query;
        ru.fragment = child.fragment;
    
        // 5.2 (4): Authority
        if (child.authority == null) {
            ru.authority = base.authority;
            ru.host = base.host;
            ru.userInfo = base.userInfo;
            ru.port = base.port;
    
            String cp = (child.path == null) ? "" : child.path;
            if ((cp.length() > 0) && (cp.charAt(0) == '/')) {
                // 5.2 (5): Child path is absolute
                ru.path = child.path;
            } else {
                // 5.2 (6): Resolve relative path
                ru.path = resolvePath(base.path, cp, base.isAbsolute());
            }
        } else {
            ru.authority = child.authority;
            ru.host = child.host;
            ru.userInfo = child.userInfo;
            ru.host = child.host;
            ru.port = child.port;
            ru.path = child.path;
        }
    
        // 5.2 (7): Recombine (nothing to do here)
        return ru;
    }
    
    1. 是否是非透明URI,如果是,则直接返回child。
    2. 判断child是否只有fragment(片段标识)。如果child只有片段标识则执行2.1。否则执行3。
      2.1 如果child的fragment和base的片段标识一样,就直接返回base的url
      2.2 把base不包含fragment的部分和child的fragment构造一个新的URI返回。
    3. 判断child的scheme不为空则直接返回child。不为空说明他是绝对路径。
    4. 根据base的URI各部分构造child的绝对路径URI并返回。

    relativize 方法

    relativize 方法可以将绝对路径的URI转换成相对路径的URI。

    URI a = URI.create("http://localhost:8080/");
    URI b = URI.create("http://localhost:8080/index.html");
    URI c = a.relativize(b);
    System.out.println(c);
    

    获取b相对a的相对路径。

    打印的结果为:index.html

    private static URI relativize(URI base, URI child) {
        // check if child if opaque first so that NPE is thrown
        // if child is null.
        if (child.isOpaque() || base.isOpaque())
            return child;
        if (!equalIgnoringCase(base.scheme, child.scheme)
            || !equal(base.authority, child.authority))
            return child;
    
        String bp = normalize(base.path);
        String cp = normalize(child.path);
        if (!bp.equals(cp)) {
            if (!bp.endsWith("/"))
                bp = bp + "/";
            if (!cp.startsWith(bp))
                return child;
        }
    
        URI v = new URI();
        v.path = cp.substring(bp.length());
        v.query = child.query;
        v.fragment = child.fragment;
        return v;
    }
    
    1. 判断child是否不是透明URI,如果不是则直接返回child。不是层次结构的uri是没有相对路径的。
    2. 判断两个URI的scheme和授权机构是否不同,如果不同则直接返回child。
    3. 判断base是否“/”结尾,如果不是则加上“/”
    4. 判断child是否以base开头,如果不是则直接返回child。
    5. 返回child中,不包含base的部分,构造一个新URI返回。


    作者:jijs
    链接:https://www.jianshu.com/p/24a2da876372
    来源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    Kinect 开发 —— 硬件设备解剖
    Kinect 开发 —— 引言
    (转)OpenCV 基本知识框架
    OpenCV —— 摄像机模型与标定
    OpenCV —— 跟踪与运动
    OpenCV —— 图像局部与分割(二)
    OpenCV —— 图像局部与部分分割(一)
    OpenCV —— 轮廓
    OpenCV —— 直方图与匹配
    OpenCV —— 图像变换
  • 原文地址:https://www.cnblogs.com/AaronBear/p/10552939.html
Copyright © 2011-2022 走看看