URLConnection是一个功能强大的抽象类,它表示指向URL指定资源的活动连接。

  • 与URL类相比,它与服务器的交互提供了更多的控制机制。尤其服务器是HTTP服务器,可以使用URLConnection对HTTP首部的访问,可以配置发送给服务器的请求参数。当然也可以通过它读取服务器的数据以及向服务器写入数据
  • URLConnection是Java的协议处理器机制的一部分。协议处理器机制是将处理协议的细节与特定数据类型分开。如果要实现一个特定的协议,则实现URLConnection的子类即可。程序运行时可以将该子类作为一个具体的协议处理器来使用。

使用URLConnection类的步骤

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

打开URLConnection

通过URL类来打开一个URLConnection

当我们拿到一个URLConnection对象后,并不代表客户端已经和服务器建立了连接。只有主动调用其connect()方法才去和服务器建立连接。不过当我们调用getInputStream(),getContent(),getHeaderField()和其他要求打开连接的方法时,如果连接尚未打开,它们就会调用connect()。所以,在实际开发中我们主动调用connect()方法的机会很少。

读取服务器的数据

这里从HTTP服务器读取数据。

获取首部


HTTP响应的首部中包含了许多有用的信息,比如消息体的类型,长度,采用的压缩格式的。只有通过解析首部中的元数据,我们才能正确的解读消息体中的信息。

获取Content-Type属性

Content-Type指定了消息体的类型(text,image,video),如果是文本类型还会指定编码方式。

public String getContentType()

程序中查找charset的值来获取编码方式,并使用指定的编码方式从流中读取数据。

下面是服务器端代码,通过header方法来指定文本编码方式。并通过iconv函数将“这个一个中文测试”以gb2312编码的方式输出。

获Content-Length长度

我们可以使用URL的openStream()方法从HTTP服务器下载文本文件。但是在实际中会产生问题,即HTTP服务器并不总是会在数据发送完后就立即关闭连接。因此,客户端不知道何时停止读取。最好的做法就是读取HTTP头中的Content-Lenght来确定文件的长度,然后根据这个长度来读取相应的字节数。

public int getContentLength()

下面的代码中我们从http://www.xdysite.cn/download.php下载一个20M大小的文件。通过解析HTTP头可以获取文件具体的大小以及文件名。然后在本地创建一个同名文件,并将获取的数据写的该文件中。因为下载的是图片,我们直接使用字符流即可。

服务器端代码

其他方法

public String getContentEncoding()   获取消息体的压缩方式,一般情况下会对消息体压缩后再传输

public long getDate()                          获取文档发送时间,该时间为自1970年1月1号0点到目前为止过去的毫秒数

public long getLastModified()             获取文档的最后修改日期

public String getHeaderField(String name)  获取任意首部字段

缓存


下面的几个首部会影响客户端的缓存(针对HTTP1.1)

Cache-control

---max-age=[seconds]     从现在起数据在缓存中待的时间

---s-maxage=[seconds]   从现在起数据在共享缓存(http代理)中待的时间,会将max-age设置覆盖

---public                         该响应可以被缓存,主要是针对HTTP代理

---private                        该响应只能被浏览器缓存,不能被代理缓存

---no-cache                     该响应可以被缓存,但是客户端再次从缓存中加载该页面时,需要用ETag或Last-modified首部去验证这个页面在服务器是否发生改变

---no-store                     不能被缓存

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

Etag                                 对资源的唯一标识,当资源发生改变时该表示也应做出改变。客户端可以使用HEAD请求来检查这个标识,只有当本地缓存的副本的ETag与请求到的不同时,才会真正的执行GET获取资源

JAVA本身是并没有实现缓存,只是对外提供了接口。至于缓存具体的实现方式需要用户自己去实现。与缓存有关的类是ResponseCache

通过该类可以安装系统级缓存。系统级缓存是一个共享缓存,且是唯一的一个。即所有请求过的URL都放在这个缓存管理器中被统一管理。当通过该类安装了缓存后,只要系统尝试加载一个新的URL时,它首先会在这个缓存中查找。如果缓存中返回了所要的内容,URLConnection就不需要与远程服务器连接了。如果没有找到,则会连接服务器下载数据。完成之后,它会把这个响应放到缓存中,使得下一次加载这个URL时,可以很快从缓存中得到这个内容。

public abstract class ResponseCache

ResponseCache是一个抽象类,它有两个抽象方法需要用户去实现。

public abstract CacheResponse get(URI uri, String rqstMethod, Map<String,List<String>> rqstHeaders)

public abstract CacheRequest put(URI uri, URLConnection conn)

get方法是从缓存取数据,它返回一个CacheResponde对象。该对象中包含了一个InputStream流,这样系统可以从该流中读取数据,然后返回给用户。put方法是往缓存中放入数据,它返回的是一个CacheRequest。该对象中包含了一个OutputStream,系统可以将从服务器获得的数据通过该流写到一个具体的地方(可以是文件可以是内存,这个需要通过我们自己实现的CacheRequest类来制定)

为了实现这两个方法需要实现CacheRequest类和CacheResponse类。下面是一个具体的例子来实现HTTP缓存。我们将会在内存中开辟一块地方作为缓存使用。

实现自己的CacheRequest类

该类用于缓存数据,将来的从服务器获取的数据都会放到该类中

实现自己的CacheResponsel类

该类主要是记录响应头和缓冲区的引用

实现MemoryCache类

class MemoryCache extends ResponseCache {
//创建容器来管理缓冲区
private final Map<URI, SimpleCacheResponse> responses
= new ConcurrentHashMap<>();
//缓冲区最大缓存URL的数量
private final int maxEntries;
</span><span style="color: #0000ff">public</span><span style="color: #000000"> MemoryCache(){
</span><span style="color: #0000ff">this</span>(100<span style="color: #000000">);
} </span><span style="color: #0000ff">public</span> MemoryCache(<span style="color: #0000ff">int</span><span style="color: #000000"> i) {
maxEntries </span>=<span style="color: #000000"> i;
} </span><span style="color: #008000">//</span><span style="color: #008000">从缓冲区读数据</span>

@Override

public CacheResponse get(URI uri, String rqstMethod,

Map<String, List<String>> rqstHeaders) throws IOException {

//如果是GET方法则去检查缓存

if ("GET".equals(rqstMethod)) {

//根据URI来获取response对象

SimpleCacheResponse response = responses.get(uri);

//有缓存对象但是已经过期,则将其从缓冲区删除并返回NULL

if (response != null && response.isExpired()) {

responses.remove(response);

response = null;

}

return response;

} else

return null;

}

</span><span style="color: #008000">//</span><span style="color: #008000">往缓冲区放数据</span>

@Override

public CacheRequest put(URI uri, URLConnection conn) throws IOException {

//检查缓存区是否达到上限

if(responses.size() >= maxEntries)

return null;

//检查是否可以缓存

CacheControl control = new CacheControl(conn.getHeaderField("Cache-Control"));

if(control.isNoCache())

return null;

else if (conn.getDoOutput()) //POST方法不缓存

return null;

//创建request对象来作为缓存

SimpleCacheRequest request = new SimpleCacheRequest();

//创建response对象并将其与request对象绑定

SimpleCacheResponse response = new SimpleCacheResponse(request, conn, control);

//将URI与response绑定

responses.put(uri, response);

//返回request对象,因为要将服务器数据写到缓存中

return request;

}

}

测试类

在测试类中,我们设置了缓存策略,然后向服务器发起了两次请求。下面是服务器的日志记录

在日志记录中我们看出只有一条请求,这是因为第一次缓存中没有数据,所以需要去服务器拿数据。而第二次请求发现同样的资源已经被缓存过了,所以只需要从缓存中直接获取即可。

URLConnection类中的setDefaultUseCaches方法可以设置对于当前的URL是否使用缓存。

URLConnection类介绍的更多相关文章

  1. URLConnection类详解-转

    转-http://www.cnblogs.com/shijiaqi1066/p/3753224.html 1. URLConnection概述 URLConnection是一个抽象类,表示指向URL指 ...

  2. CYQ.Data.Orm.DBFast 新增类介绍(含类的源码及新版本配置工具源码)

    前言: 以下功能在国庆期就完成并提前发布了,但到今天才有时间写文介绍,主要是国庆后还是选择就职了,悲催的是上班的地方全公司都能上网,唯独开发部竟不让上网,是个局域网. 也不是全不能上,房间里有三台能上 ...

  3. MediaRecorder类介绍

    audiocallbackvideojavadescriptorencoding 目录(?)[+] 找到个MediaRecorder类介绍和大家分享一下. Mediarecorder类在官网的介绍和在 ...

  4. Object类介绍

    一.Object类介绍

  5. istringstream、ostringstream、stringstream 类介绍 .

    istringstream.ostringstream.stringstream 类介绍 . 转自:http://www.cnblogs.com/gamesky/archive/2013/01/09/ ...

  6. URLConnection类详解

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/3753224.html ...

  7. C#中的Dictionary字典类介绍

      Dictionary字典类介绍 必须包含名空间System.Collection.Generic    Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值)    键必须是 ...

  8. POI 导出导入工具类介绍

    介绍: Apache POI是Apache软件基金会的开源项目,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. .NET的开发人员则可以利用NPOI (POI ...

  9. Android Paint类介绍以及浮雕和阴影效果的设置

    Paint类介绍 Paint即画笔,在绘制文本和图形用它来设置图形颜色, 样式等绘制信息. 1.图形绘制 setARGB(int a,int r,int g,int b); 设置绘制的颜色,a代表透明 ...

随机推荐

  1. AngularJS在IE8的支持

    AngularJS一般不会选择IE8支持, 因为很多特性在IE8下效果很差, 性能也不好, 但是由于项目的需要, 客户的机器有些是XP, 只能够装IE8, 所以为了解决这个, 我查阅了相关的资料,发现 ...

  2. swift实现饭否应用客户端源码

    swift 版 iOS 饭否客户端 源码下载:http://code.662p.com/view/13318.html 饭否是中国大陆地区第一家提供微博服务的网站,被称为中国版Twitter.用户可通 ...

  3. The operation couldn’t be completed. (LaunchServicesError error 0.)

    问题描述: 当运行Xcode时,编译代码成功,但是登陆模拟器失败,显示错误:The Operation couldn't be completed.(LaunchServicesError error ...

  4. 基于pygtk的linux有道词典

    基于pygtk的linux有道词典 一.桌面词典设计 想把Linux用作桌面系统,其中一部分障碍就是Linux上没有像有道一样简单易用的词典.其实我们完全可以自己开发一款桌面词典, 而且开发一款桌面词 ...

  5. C#实现在图片上斜着写字

    最近公司要搞微信活动页面,要实现图片上可以写自己名字的功能,于是就查了一下怎么实现,下面贴一下代码备忘,希望大家也能用到: 我是在控制台应用程序里进行试验的. using (Image bitmap ...

  6. MS SQL 需要定期清理日志文件

    前言碎语 关于对SQL SERVER 日志文件管理方面了解不多的话,可以参考我的这篇博客文章“MS SQL 日志记录管理”,不过这篇文章只是介绍对SQL SERVER日志记录的深入认知了解,并没有提出 ...

  7. SQL Server 列存储索引强化

    SQL Server 列存储索引强化 SQL Server 列存储索引强化 1. 概述 2.背景 2.1 索引存储 2.2 缓存和I/O 2.3 Batch处理方式 3 聚集索引 3.1 提高索引创建 ...

  8. MySQL的loose index scan

    众所周知,InnoDB采用IOT(index organization table)即所谓的索引组织表,而叶子节点也就存放了所有的数据,这就意味着,数据总是按照某种顺序存储的.所以问题来了,如果是这样 ...

  9. [百度经验]window下连接mysql 错误代码 1045

    连接mysql时出现错误代码 1045 Access denied for user 'root'@'localhost' (using password:YES) 百度经验:jingyan.baid ...

  10. 【小白的CFD之旅】07 CFD常识

    学了一周的流体力学,小白对于流体力学有了基本的了解,但是流体力学涵盖的内容何其之多,一周的时间怎么可能学得好呢,很多的概念都是模棱两可.为了在一个月之后能够应用CFD,小白又找到了黄师姐. “师姐,看 ...