【网络编程】——Java实现(2)——URL与Connection

这里是Java网络编程Java Socket编程相关的学习手记。这里按照官方的Java 8 Toturial教程的Custom Networking学习路径,对相关的一些内容进行解读(并不完全,如果有错请联系我,谢谢^ _ ^),同时在学习的过程中加入个人的理解与对代码运行的思考。

下面是整个专栏的文章链接,用于快速的导航。

摘要及说明

原文链接:Working with URLs这里会根据具体情况进行相关内容的省略。

注意:文章有Java 8 IO相关API的使用,不过也不复杂

URL

很简单,这里做简单介绍。
URL(Uniform Resource Locator),统一资源定位,互联网上资源的引用/链接。

组成部分:

  • 协议(Protocol),如http
  • 资源名,协议后面的

资源名又由很多部分组成,而主机名,端口号,文件名是常见元素

简单例子:https://docs.oracle.com/javase/tutorial/networking/urls/index.html

  • 协议名:https
  • 主机名:docs.oracle.com
  • 端口号:这里默认为80。即https://docs.oracle.com:80/javase/tutorial/networking/urls/index.html
  • 文件名:/javase/tutorial/networking/urls/index.html。其中包含路径与文件名。

使用URL类——创建

创建URL类,有几种构造器,最简单的当然是通过字符串String来创建

  • URL(String spec)——创建字符串表示的URL对象
    • URL url = new URL("http://baidu.com");
  • URL(URL baseURL, String relativeURL)——相对URL

例如下两个URL,可表示为

还有其它构造器,通过制定特定的URL成分来构造URL对象:

URL(String protocol, String host, int port, String file);
URL(String protocol, String host, String file);

除此之外官方的API中还有如下的构造器,暂时不详解,列出:

URL(String protocol, String host, int port, String file, URLStreamHandler handler)
URL(URL context, String spec, URLStreamHandler handler)

注意点:

  • 每次new URL时都需要捕获异常。如下是一个简单的例子:

    try {
        URL url = new URL("http://example.com/");
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
    
  • URL是"write-once"对象。也就是说,一旦你创建了一个URL对象,你就不能改变它的任何属性,如protocol(协议), host name(主机名), filename(文件名/路径), port number(端口号)

使用URL类——解析

我们能使用类似getXXX方法来获取URL对象的信息。这些信息对应于我们之前在构造器的一些参数。
URL对象对象的所有get方法
URL get method

尝试下面的代码,通过下面的代码,对于URL的各种字段都能有一个清晰的了解:

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import java.net.*;
import java.io.*;

public class ParseURL {
    public static void main(String[] args) throws Exception {

        URL aURL = new URL("http://example.com:80/docs/books/tutorial"
                           + "/index.html?name=networking#DOWNLOADING");

        System.out.println("protocol = " + aURL.getProtocol());
        System.out.println("authority = " + aURL.getAuthority());
        System.out.println("host = " + aURL.getHost());
        System.out.println("port = " + aURL.getPort());
        System.out.println("path = " + aURL.getPath());
        System.out.println("query = " + aURL.getQuery());
        System.out.println("filename = " + aURL.getFile());
        System.out.println("ref = " + aURL.getRef());
    }
}

/**输出结果
protocol = http
authority = example.com:80
host = example.com
port = 80
path = /docs/books/tutorial/index.html
query = name=networking
filename = /docs/books/tutorial/index.html?name=networking
ref = DOWNLOADING
**/

使用URL类——直接从URL读数据

在成功创建URL对象后,可以直接调用URL的openStream() 方法获取 java.io.InputStream 对象,也就是说我们能很简单地直接读取URL的内容。

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import java.net.*;
import java.io.*;

public class URLReader {
    public static void main(String[] args) throws Exception {

        URL oracle = new URL("https://www.oracle.com/index.html");
        //URL oracle = new URL("http://www.oracle.com/");

        BufferedReader in = new BufferedReader(
                new InputStreamReader(oracle.openStream()));

        String inputLine;
        while ((inputLine = in.readLine()) != null)
            System.out.println(inputLine);
        in.close();
    }        
}

很容易知道,上面的打印结果为网站的html代码。值得注意的是:官方教程第一行代码为:
URL oracle = new URL("http://www.oracle.com/");
我运行之后,发现什么也没有输出来。于是我打开浏览器,输入该网址http://www.oracle.com/。浏览器重定位到https://www.oracle.com/index.html网站。所以我把上面例子中的URL改为此链接,运行成功,输出html代码。

具体原因我没有分析,我猜应该是重定向的问题,而url的openStream并不能追踪重定向,所以返回空?

当然这是个人猜想,具体如果我找到原因,再贴出来。各位有谁清楚的话,可以留言或者@我,canliture@outlook.com哦,谢谢 ^ _ ^。

使用URL类——创建连接

在成功创建URl对象之后,我们可以调用URL对象的openConnection 方法来获得一个URLConnection对象。或者它的特定协议的子类对象,例如java.net.HttpURLConnection

在我们使用URLConnection 连接之前,我们可能会设置参数或者一些请求属性。当调用URLConnection.connect方法的时候,
会初始化一条通信链路,下面是一个代码实例:

try {
    URL myURL = new URL("http://example.com/");
    URLConnection myURLConnection = myURL.openConnection();
    myURLConnection.connect();
} 
catch (MalformedURLException e) { 
    // new URL() failed
    // ...
} 
catch (IOException e) {   
    // openConnection() failed
    // ...
}

代码中,通过调用openConnection()方法,能够返回一个新创建的URLConnection对象。

我们并不总是需要显示地调用connect方法来建立连接,像getInputStream, getOutputStream,等操作在必要的时候会隐式地执行连接。例如上面的代码并不需要openConnection,却能读出请求内容,代码可以查看下一小结的代码示例(从URLConnection读)

在成功地连接之后,我们能使用URLConnection 对象来执行一些操作,像读,写等。下面的内容会有讲解。

URLConnection类——读写

URLConnection 类包含许多让你使用URL来在网络间通信的方法。URLConnection 是一个以HTTP为中心的类,意思就是说,它的许多方法只工作在HTTP形式的URL下。然而,大多数的URL协议能让你从连接中读写,这部分就讲解了读写这两部分。

从URLConnection读

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import java.net.*;
import java.io.*;

public class URLConnectionReader {
    public static void main(String[] args) throws Exception {
        URL oracle = new URL("https://www.oracle.com/index.html");
        URLConnection yc = oracle.openConnection();
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                    yc.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) 
            System.out.println(inputLine);
        in.close();
    }
}

注意这里的代码示例与上面的使用URL类——直接从URL读数据代码的对比。这里是显式地获取得以URLConnection连接然后从连接中获取input Stream。其中通过调用getInputStream,连接时隐式地建立。

直接从URL获取内容,或者通过URLConnection来读取内容,在实现功能上没有差别。但是URLConnection用处更大,因为它还能在从URL读取内容的同时进行其它的操作,如写操作。

向URLConnection写

这里的“写”,HTTP中一般指请求参数

这里官方给了一个对HTML与服务器通信的简单例子:

许多HTMl页面包含表单(form)——文本域,或者其它的需要发给服务器端的填写字段。在你点击提交按钮表单的按钮时,浏览器会写入数据到URL。在另一端的服务器收到数据并处理,然后返回响应,通常是以一个新的页面的形式返回。

在许多情况下,提交表单的方式叫做”HTTP POST“,POST数据给服务端。这种方法叫做”POST to A URL“。服务端识别此POST请求,并读取客户端发来的数据。

Java 程序和服务端交互通常通过如下几个步骤:

  • 1,创建URL类的对象(Create a URL)
  • 2,从URL中获得一个URLConnection(Retrieve the URLConnection object)
  • 3,设置在此URLConnection连接能够进行输出(写)操作{ connection.setDoOutput(true); }(Set output capability on the URLConnection)
  • 4,打开URL资源的连接(Open a connection to the resource)
  • 5,从资源连接中获取一个输出流(Get an output stream from the connection)
  • 6,写内容到输出流中(Write to the output stream)
  • 7,关闭输出流(Close the output stream.)

下面是一个简单的实践程序代码:

/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */ 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;

public class Main {

    public static void main(String[] args) throws Exception {

        if (args.length != 2) {
            System.err.println("Usage:  java Reverse "
                    + "http://<location of your servlet/script>"
                    + " string_to_reverse");
            System.exit(1);
        }

        String stringToReverse = URLEncoder.encode(args[1], "UTF-8");

        URL url = new URL(args[0]);
        URLConnection connection = url.openConnection();
        connection.setDoOutput(true);

        OutputStreamWriter out = new OutputStreamWriter(
                connection.getOutputStream());
        out.write("string=" + stringToReverse);
        out.close();

        BufferedReader in = new BufferedReader(
                new InputStreamReader(
                        connection.getInputStream() ) );

        String decodedString;
        while ((decodedString = in.readLine()) != null) {
            System.out.println(decodedString);

        }
        in.close();

    }
}

程序用法很简单,要以命令行的形式运行,因为要命令行参数来作为执行参数。下面以百度网址为例,运行例子。

  • 假设代码文件为Main.java
  • 查看程序代码容易知道,运行的时候,我们需要加一个运行参数“string_to_reverse”
  • D:\src>javac Main.java
  • D:\src>java Main http://www.baidu.com/ string_to_reverse

对于咱们中文用户来说,查看输出,有坑啊!!乱码!!
查询资料。知道,我们的输出流需要设置编码,代码改进如下

/**
.....
out.close();
**/
BufferedReader in = new BufferedReader(
        new InputStreamReader(
                connection.getInputStream(), "UTF-8") );
/**
String decodedString;
.....
**/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值