简介

  • URI:Uniform Resource Identifier,统一资源标识符,URI的范畴位于顶层,URL和URN只是子范畴。
  • URL: Uniform Resource Locator,代表资源的地址信息
  • URN:Uniform Resource Name,代表某个资源独一无二的名称。
  • 对于程序员来说,URI和URL都是一个意思。
  • 它们的主要格式为:一串以scheme开头的字符串,语法如下:

    [scheme:] scheme-specific-part //<协议>:<特定协议部分>
    //特定协议部分的格式
    //<用户>:<密码>@<主机>:<端口号>/<路径>
    
  • 举个栗子
  • 若主机名为openhome.cc,要获取Gossip中的index.html,端口号是8080.则必须使用以下URL:

    http://openhome.cc:8080/Gossip/index.html
    
  • 又假设想获取本地计算机文件系统中C://workspace下的jdbc.pdf,则为:

    file://C://workspace/jsbc.pdf
    
  • 协议指定了以何种方式获取资源。一些协议名的例子:

    • ftp(File Transfer Protocol)文件传输协议
    • http(Hypertext Tranfer Protocol)超文本传输协议
    • mailto 电子邮件
    • file 特定主机文件名
  • 相对URL如:articles/articels.html,是依赖于标识符出现的环境而言的。

    用法

  • URI类只能解析路径,不包含任何用于访问资源的方法。
  • URL类则可以打开一个到达资源的流,访问资源。
  • 用String构建URI对象

    URI uri=new URI("http://www.cnn.com"); //URI会把String分解为组件存于各个属性中,String不合法则抛URISyntaxException异常
    //效果同上
    URI uri=URI.create("http://www.cnn.com");
    
  • URL类:可以用URI的toURL()获取URL对象,也可以直接new

    URL url=new URL("http://www.cnn.com");
    
  • openstream():获取流,读取资源

    URL url = new URL (args [0]);
    InputStream is = url.openStream ();
    int ch;
    while ((ch = is.read ()) != -1) {
      System.out.print ((char) ch);
    }
    
  • 如果是html形式的文本,则打印:

    <html>
    …
    </html>
    
  • getContent():返回资源对应的对象,调用instanceof方法检查是否为预期对象之后可以针对性地采用处理流来读取资源

    URL url = new URL (args [0]);
    Object o = url.getContent ();
    if (o instanceof ImageProducer) { //如果资源是JPEG资源的话,获取到的对象应该实现了ImageProducer接口
      ImageProducer ip = (ImageProducer) o;
      // ...
    }
    
  • openConnection():返回URLConnection对象,封装了与资源连接的信息,有点像发起了一个请求,连接到资源后得到了响应。

    public static void main (String[] args) throws IOException {
        URL url = new URL ("http://www.javajeff.com"); //http://www.javajeff.com
        // 返回代表某个资源的连接的新的特定协议对象的引用
        URLConnection uc = url.openConnection ();
        // 进行连接
        uc.connect ();
        // 打印header的内容
        Map m = uc.getHeaderFields (); //获取header报头中的键值对
        Iterator i = m.entrySet ().iterator ();
        while (i.hasNext ()) {
            System.out.println (i.next()); //自动按键=值的形式输出
        }
        // 检查是否资源允许输入和输出操作
        System.out.println ("Input allowed = " +uc.getDoInput ());
        System.out.println ("Output allowed = " +uc.getDoOutput ());
    }
    
  • 打印

    Date=[Sun, 17 Feb 2002 17:49:32 GMT]
    Connection=[Keep-Alive]
    Content-Type=[text/html; charset=iso-8859-1]
    Accept-Ranges=[bytes]
    Content-Length=[7214]
    null=[HTTP/1.1 200 OK]
    ETag=["4470e-1c2e-3bf29d5a"]
    Keep-Alive=[timeout=15, max=100]
    Server=[Apache/1.3.19 (Unix) Debian/GNU]
    Last-Modified=[Wed, 14 Nov 2001 16:35:38 GMT]
    Input allowed = true
    Output allowed = false
    
  • 其中ContentType和input/output allowed比较有用
  • 可以用java代码而不是form表单向url提交请求,数据必须是键值对形式,而且按照编码规则来

    String result = URLEncoder.encode ("a b"); //将把空格转换为+号
    
  • 把数据发送给某个资源

    class URLDemo3 {
        public static void main (String [] args) throws IOException {
            URL url = new URL("http://banshee.cs.uow.edu.au:2000/~nabg/echo.cgi");
            URLConnection uc = url.openConnection ();
            // 验证连接的类型,必须是HttpURLConnection的
            if (!(uc instanceof HttpURLConnection)) {
              System.err.println ("Wrong connection type");
              return;
            }
            //默认不支持发送数据,这里改为支持
            uc.setDoOutput (true);
            // 不使用cache
            uc.setUseCaches (false);
            //设置Content-Type指示指定MIME类型
            uc.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded"); //单纯键值对的话就必须是这种类型
            // 建立名/值对内容发送给服务器
            String content = buildContent (args);
            //设置Content-Length
            uc.setRequestProperty ("Content-Length", "" + content.length ());
            // 连接的适当类型
            HttpURLConnection hc = (HttpURLConnection) uc;
            // 把HTTP请求方法设置为POST(默认的是GET)
            hc.setRequestMethod ("POST");
            // 输出内容
            OutputStream os = uc.getOutputStream ();
            DataOutputStream dos = new DataOutputStream (os);
            dos.writeBytes (content);
            dos.flush ();
            dos.close ();
            // 从服务器程序资源输入和显示内容
            InputStream is = uc.getInputStream ();
            int ch;
            while ((ch = is.read ()) != -1)
              System.out.print ((char) ch);
            is.close ();
        }
    
        static String buildContent (String [] args) { //参数:name value name value name value
            StringBuffer sb = new StringBuffer ();
            for (int i = 0; i < args.length; i++) {
              // 对参数编码
              String encodedItem = URLEncoder.encode (args [i]);
              sb.append (encodedItem);
              if (i % 2 == 0)
                sb.append ("="); // 分离名称和值
              else
                sb.append ("&"); // 分离名称/值对
            }
            // 删除最后的 & 间隔符
            sb.setLength (sb.length () - 1);
            return sb.toString ();
        }
    }
    
  • 输出

    <html>
    <head>
        <title>Echoing your name value pairs</title>
    </head>
    <body>
        <ol>
            <li>name1 : value1
            <li>name2 : value2
            <li>name3 : value3
        </ol>
        <hr>
        Mon Feb 18 08:58:45 2002
    </body>
    </html>
    
  • URI的作用之一:解析标识符并将它分解为各种不同的部分,可以用一下方法读取各个部分:
    • getScheme
    • getSchemeSpecificPart
    • getAuthority
    • getUserInfo
    • getHost
    • getPort
    • getPath
    • getQuery
    • getFragment
  • 另一个作用:处理绝对标识符和相对标识符