URLConnection

简介

URLConnection是一个抽象类,表示指向URL指定资源的活动连接。URLConnection有两个不同但相关的用途:

  • URLConnection可以检查服务器发送的首部,并相应地做出响应。它可以设置客户端请求中使用的首部字段。最后URLConnection可以用POST、PUT和其他HTTP请求方法向服务器发回数据;
  • URLConnection类是Java的协议处理器机制的一部分;

打开URLConnection

直接使用URLConnection类的程序遵循以下基本步骤:

  1. 构造一个URL对象;
  2. 调用这个URL对象的openConnection()获取一个对应该URL的URLConnection对象;
  3. 配置这个URLConnection;
  4. 读取首部字段;
  5. 获得输入流并读取数据;
  6. 获得输出流并写入数据;
  7. 关闭连接;

并不一定执行所有这些步骤。看你需不需要!
URLConnection类仅有的一个构造函数为保护类型:

protected URLConnection(URL url)
try {
			URL url = new URL("http://www.baidu.com");
			URLConnection connection = url.openConnection();
			//从URL读取。。。
		} catch (Exception e) {
			// TODO: handle exception
		}

读取服务器的数据

下面是使用URLConnection对象从一个URL获取数据所需的最起码的步骤:

  1. 构造一个URL对象;
  2. 调用这个URL对象的openConnection()方法,获取对应该该URL的URLConnection对象;
  3. 调用这个URLConnection的getInputStream()方法;
  4. 使用通常的流API读取输入流;

getInputStream()方法返回一个通用InputStream,可以读取和解析服务器发送的数据:

public class Test {

	public static void main(String[] args) {
		try {
		    //打开URLConnection进行读取
			URL url = new URL("http://www.baidu.com");
			URLConnection connection = url.openConnection();
			try (InputStream in = connection.getInputStream()){    //带资源的try-catch语句。自动关闭
				InputStream buffer = new BufferedInputStream(in);
				//将InputStream串链到一个Reader
				Reader reader = new InputStreamReader(buffer);
				int c;
				while ((c = reader.read())!= -1) {
					System.out.print((char)c);
				}
			} catch (MalformedURLException e) {
				
			}
		} catch (IOException e) {
			
		}
	}	
}

运行:
在这里插入图片描述
URL和URLConnection这两个类最大的不同在于:

  • URLConnection提供了对HTTP首部的访问;
  • URLConnection可以配置发送给服务器的请求参数;
  • URLConnection除了读取服务器数据外,还可以向服务器写入数据;

读取指定的首部字段

前6个方法可以请求首部中特定的常用字段:

  • Content-Type
  • Content-Length
  • Content-encoding
  • Date
  • Last-modified
  • Expires

public String getContentType()
getContentType()方法返回响应主体的MIME内容类型。如果没有提供内容类型,它不会抛出异常,而是返回null;

public int getContentLength()
getContentLength()方法告诉你内容中有多少字节。如果没有Content-Length首部,getContentLength()就返回-1;

public long getContentLengthLong()--------Java7增加的
与getContentLength()类似,只不过它会返回一个long而不是int,这样就可以处理更大的资源;

public String getContentEncoding()
getContentEncoding()方法返回一个String,指出内容是如何编码的。如果发送的内容没有编码,这个方法就返回null;

public long getDate()
getDate()方法返回一个long,指出文档何时发送;

public long getExpiration()
有些文档有基于服务器的过期日期,指示应当何时从缓存中删除文档,并从服务器重新下载。如果HTTP首部没有包括Expiration字段,getExpiration()就返回0,这表示文档不会过期,将永远保留在缓存中;

public long getLastModified()
返回文档的最后修改日期;
Test .java

public class Test {

	public static void main(String[] args) {
		try {
			URL url = new URL("http://www.baidu.com");
			URLConnection connection = url.openConnection();
			System.out.println("Content-Type: " + connection.getContentType());
			System.out.println("Content-Length: " + connection.getContentLength());
			System.out.println("Content-LengthLong: " + connection.getContentLengthLong());
			System.out.println("Content-encoding: " + connection.getContentEncoding());
			System.out.println("Date: " + connection.getDate());
			System.out.println("Expires: " + connection.getExpiration());
			System.out.println("Last-modified: " + connection.getLastModified());
		} catch (IOException e) {
			
		}
	}	
}

URLConnection_第1张图片

获取任意首部字段

public String getHeaderField(String name)
getHeaderField()方法返回指定首部字段的值。首部的名不区分大小写,也不包含结束冒号;

URL url = new URL("http://www.baidu.com");
URLConnection connection = url.openConnection();
System.out.println(connection.getHeaderField("Content-Type"));
System.out.println(connection.getHeaderField("last-modified"));

//输出
text/html
Mon, 23 Jan 2017 13:27:36 GMT

public String getHeaderFieldKey(int n)
返回第n个首部字段的键(即字段名)。请求方法本身是第0个首部,它的键为null。第一个首部即编号为1:

System.out.println(connection.getHeaderFieldKey(5));    //输出Content-Type

public String getHeaderField(int n)
返回第n个首部字段的值,包含请求方法和路径的起始行是第0个首部字段,实际的第一个首部编号为1:
Test.java–循环显示整个HTTP首部

public class Test {

	public static void main(String[] args) {
		try {
			URL url = new URL("http://www.baidu.com");
			URLConnection connection = url.openConnection();
			for (int i = 1; ; i++) {
				String header = connection.getHeaderField(i);
				if (header == null) {
					break;
				}
			System.out.println(connection.getHeaderFieldKey(i)+": "+header);	
			}
		} catch (IOException e) {
			
		}
	}	
}

//输出
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: Keep-Alive
Content-Length: 2381
Content-Type: text/html
Date: Thu, 04 Oct 2018 13:14:20 GMT
Etag: "588604ec-94d"
Last-Modified: Mon, 23 Jan 2017 13:28:12 GMT
Pragma: no-cache
Server: bfe/1.0.8.18
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/

public long getHeaderFieldDate(String name, long Default)
这个方法首先获取由name参数指定的首部字段,然后尝试将这个字符串转换为一个long;

public long getHeaderFieldInt(String name, int Default)
这个方法获取首部字段name的值,尝试将其转换为int;

缓存

默认情况下,一般认为使用GET通过HTTP访问的页面可以缓存,也应当缓存。使用HTTPS或POST访问的页面通常不应缓存。不过,HTTP首部可以对此做出调整:
URLConnection_第2张图片

  • Last-modified首部指示资源最后一次修改的日期。客户端可以使用一个HEAD请求来检查这个日期,只有当本地缓存的副本早于Last-modified日期时,它才会真正执行GET来获取资源;

在这里插入图片描述

Java的Web缓存

。。。用到再写;

配置连接

URLConnection类有7个保护的实例字段,定义了客户端如何向服务器做出请求:

protected URL url;
protected boolean doInput = true;
protected boolean doOutput = false;
protected boolean allowUserInteraction = defaultAllowUserInteraction;
protected boolean useCaches = defaultUseCaches;
protected long ifModifiedSince = 0;
protected boolean connected = false;

例如,如果doOutput为true,那么除了通过这个URLConnection读取数据外,还可以将数据写入到服务器。如果useCaches为false,连接会绕过所有本地缓存,重新从服务器下载文件;

由于这些字段都是保护字段,所以它们的值要通过相应的set方法和get方法来访问和修改!
只能在URLConnection连接之前修改这些字段,对于设置字段的方法,如果调用这些方法时连接已经打开,大多数方法会抛出一个IllegalStateException异常!

protected URL url
url字段指定了这个URLConnection连接的URL。可以通过getURL()方法获取这个字段的值

public class Test {

	public static void main(String[] args) {
		try {
			URL url = new URL("http://www.baidu.com");
			URLConnection connection = url.openConnection();
			System.out.println(connection.getURL());         //输出http://www.baidu.com
		} catch (IOException e) {			
		}
	}	
}

protected boolean connected
如果连接已经打开,boolean字段connected为true,如果连接关闭,这个字段则为false。由于创建一个新的URLConnection对象时连接尚未打开,所以其初始值为false。没有直接读取或改变connected值的方法。不过,任何导致URLConnection连接的方法都会将这个变量设置为true;

protected boolean allowUserInteraction
有些URLConnection需要与用户交互。allowUserInteraction字段指示了是否允许用户交互。默认值为false;

protected boolean doInput
URLConnection可以用于读取服务器、写入服务器,或者同时用于读/写服务器。如果URLConnection可以用来读取,保护类型boolen字段doInput就为true,否则为false;默认为true!

protected boolean doOutput
如果URLConnection可以用于写入,保护类型boolen字段doOutput就为true,否则为false;默认为false!

protected long ifModifiedSince
URLConnection_第3张图片
protected boolean useCaches
useCaches变量确定了是否可以使用缓存。默认值为true,表示将使用缓存;false表示不使用缓存 !!

超时

有4个方法可以查询和修改连接的超时值。也就是说,底层socket等待远程服务器的响应时,等待多长时间后会抛出SocketTimeoutException异常:

//控制socket等待建立连接的时间
public void setConnectTimeout(int timeout)
public int getConnectTimeout()

//控制输入流等待数据到达的时间
public void setReadTimeout(int timeout)
public int getReadTimeout()

都以毫秒为单位。都将0解释为永远不超时。如果超时值为负数,两个设置方法都会抛出IllegalArgumentException异常;

配置客户端请求HTTP首部

每个URLConnection会在首部默认设置一些不同的名–值对。打开连接前,可以使用setRequestProperty()方法为HTTP首部增加首部字段:

//只能在连接打开之前使用。如果连接已经打开,它将抛出一个IllegalArgumentException异常;getRequestProperty()方法返回这个
//URLConnection所用HTTP首部中指定字段的值
public void setRequestProperty(String key, String value)

HTTP允许一个指定名字的属性有多个值。在这种情况下,各个值用逗号隔开;
要增加另外一个属性值,需要使用addRequestProperty()方法:

public void addRequestProperty(String key, String value)

如果出于某种原因需要查看URLConnection中的首部,有一个标准的获取方法:

public String getRequestProperty(String key)

Java还提供了一个方法,可以获得连接的所有请求属性并作为一个Map返回:

public Map> getRequestProperties()  //键是首部名,值是属性值列表

向服务器写入数据

有时你需要向URLConnection写入数据,例如,使用POST向Web服务器提交表单,或者使用PUT上传文件。
getOutputStream()方法返回一个OutputStream,可以用来写入数据传送给服务器:

public OutputStream getOutputStream()

由于URLConnection在默认的情况下不允许输出,所以在请求输出流之前必须调用setDoOutput(true)。为一个HTTP URL将doOutput设置为true时,请求方法将由GET变为POST;

public static void main(String[] args) {
		try {
			URL url = new URL("http://www.baidu.com");			
			URLConnection connection = url.openConnection();
			connection.setDoOutput(true);
			OutputStream out = connection.getOutputStream();
			OutputStream buff = new BufferedOutputStream(out);
			OutputStreamWriter writer = new OutputStreamWriter(buff);
			writer.write("name=yd&sex=man");
			writer.flush();
			writer.close();
		} catch (IOException e) {
			
		}
	}	

URLConnection_第4张图片

HttpURLConnection

java.net.HttpURLConnection类是URLConnection的抽象子类。它提供了另外一些方法,在处理http URL时尤其有帮助;
由于这个类是抽象类,唯一的构造函数是保护类型的,所以不能直接创建HttpURLConnection的实例:

URL url = new URL("http://www.baidu.com");
URLConnection connection = url.openConnection();
HttpURLConnection http =  (HttpURLConnection) connection;

或者可以跳过一个步骤:

URL url = new URL("http://www.baidu.com");	
HttpURLConnection http =  (HttpURLConnection) url.openConnection();

请求方法

URLConnection_第5张图片
默认情况下,HttpURLConnection会使用GET方法。不过,可以用setRequestMethod()来改变请求方法:

public void setRequestMethod(String method) throws ProtocolException

这个方法的参数应当是以下7个字符之一:

  • GET:
  • POST
  • HEAD:HEAD与GET相似。不过,它告诉服务器只返回HTTP首部;这个方法最常用的用途是检查文件在最后一次缓存之后是否有修改;
  • PUT:这个方法允许客户端将文档放在网站的抽象层次结构中,而不需要知道网站如何映射到实际的本地文件系统;
  • DELETE:DELETE方法将删除Web服务器上位于指定URL的文件;
  • OPTIONS:OPTIONS请求方法询问某个特定URL支持哪些选项。如果请求的URL是星号(*),那么这个请求将应用于整个服务器而不是服务器上的某个URL;
  • TRACE:TRACE请求方法会发送HTTP首部,服务器将从客户端接收这个HTTP首部;

如果使用其他方法,就会抛出java.net.ProtocolException异常,这是IOException的一个子类;

断开与服务器的连接

HTTP1.1支持持久连接,允许通过一个TCP socket发送多个请求和响应。HttpURLConnection类透明地支持HTTP Keep-Alive,除非显式将其关闭。一旦知道与一个特定主机的会话结束,disconnect()方法允许客户端断开连接:

public abstract void disconnect()

如果这个连接上还有打开的流,disconnect()将关闭这些流。不过,反过来并不成立。关闭一个持久连接上的流时,并不会关闭这个socket并断开连接;

处理服务器响应

通常响应消息中我们只需要数字响应码。HttpURLConnection有一个getResponseCode()方法,会以int返回这个响应码:

public int getResponseCode() throws IOException

响应码后面的文本字符串称为响应信息。可以由一个getResponseMessage()方法返回:

public String getResponseMessage() throws IOException

重定向
默认情况下,HttpURLConnection会跟随重定向。不过,HttpURLConnection有两个静态方法,允许你确定是否跟随重定向:

public static boolean getFollowRedirects()
public static void setFollowRedirects(boolean set)

如果跟随重定向,getFollowRedirects()方法就会返回true,否则返回false。当参数为true时,setFollowRedirects()会让HttpURLConnection对象跟随重定向。当参数为false,则会阻止HttpURLConnection对象跟随重定向。
代理
usingProxy()方法可以指定某个HttpURLConnection是否通过代理服务器:

public abstract boolean usingProxy()

如果使用了代理,返回true,否则返回false;

以上只是学习所做的笔记!!!
书籍:Java网络编程

你可能感兴趣的:(Java网络编程)