如何写一个HttpClient[1]——URI的处理
2016-06-24 08:54
806 查看
如何写一个HttpClient[1]——URI的处理
在翻阅apache的http client的代码的时候,看到org.apache.http.client.utils.URIBuilder.java的写法,感觉甚妙。特意分析一下源码,并且对比几种不同的URI写法。本文目录
作为字符串的URI作为类对象的URI
作为Builder的URI
Apache的HttpClient
作为字符串的URI
假设我们有一个HttpClient类,这个类用来发起http请求并且做出响应。如下:
class HttpClient{ ... }
现在要把
URI作为参数,传递给
HttpClient类,好让它知道对谁发起http请求。
URI可以是诸如 https://www.google.com/#q=编程狗的博客 这样一个简单的string,一个简单的实现就是给
HttpClient类提供一个设置
URL的方法:
class HttpClient{ ... public void setURI(String uri){ ... } ... }
这应该是最简单的但却是最不成熟的做法了。它有很多弊端,但我们暂时不讲出来,且往下看。
作为类对象的URI
现在我们需要更换URI,但又不是全部更换,什么意思呢?不妨分几个部分来看看
URI:
Scheme -> https Host -> www.google.com Path -> /#q=编程狗的博客
https的可能换成
http,
www.google.com可能会换成
www.google.com.hk,
/#q=编程狗的博客可能换成其他的关键词。我们暂且把这个过程称为参数的置换。如果我们仅仅给客户端类
HttpClient提供一个
setURI(String uri)方法,上面的置换只能通过换掉整个URI实现了。比如把https://www.google.com/#q=编程狗的博客 换成 http://www.google.com/#q=编程狗的博客,而没有办法直接把"https"换成"http"。
于是,我们不妨提供再一下几个方法,以使我们很方便的做出上面的置换:
public void setScheme(String scheme){ ... } public void setHost(String host){ ... } public void setPath(String path){ ... }
这三个方法分别用来设置
scheme,
host和
path。为了叙述方便,没有对参数进行检查。仅仅提供这三个设置参数的方法是不能过实现置换的,因为对于传入的URI,必须先分割成
scheme,
host和
path三部分。当然,我们可以的再添加一个
splitURI方法,实现分割;但是,我们已然发现如果这样做了,
HttpClient类就有至少4个方法处理URI了,将来可能还会增加,
HttpClient类可能会有数十个方法的作用与http信息收发不相关,这样势必是一种混乱,并且影响扩展性,因此我们不这样做。我们应当有一个
URI类,专门处理URI的置换和分割。
class URI{
//构造函数,默认把uri分割好。
public URI(String uri){
...
splitURI();
...
}
//分割方法
private void splitURI(){
...
}
//set方法
public void setScheme(String scheme){ ... } public void setHost(String host){ ... } public void setPath(String path){ ... }
//get方法
public String getScheme(){
...
return scheme;
}
public String setHost(){
...
return host;
}
public String setPath(){
...
return path;
}
}
同时我们也更新
HttpClient类:
class HttpClient{ ... public void setURI(URI uri){ ... } ... }
我们可以这样使用它们:
URI uri = new URI("https://www.google.com/#q=编程狗的博客"); uri.getScheme();// https uri.getHost();// www.google.com uri.getPath();// /#q=编程狗的博客 ... uri.setScheme();// https(如果你确实需要重新设置) ... HttpClient client = new HttpClient(); client.setURI(uri);
作为Builder的URI
到现在为止已经可以应付关于URI的很多需求了,但是我们如果要求URI类是一个不可变的类,为什么
不可变呢?因为
不可变更加安全。但那些set方法就没有用处了。apache把URI的set方法去掉了,如果想设置参数,现在只能通过构造函数:
//重载构造函数 public URI(String str){ ... } /** * @param scheme Scheme name * @param userInfo User name and authorization information * @param host Host name * @param port Port number * @param path Path * @param query Query * @param fragment Fragment */ public URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment){ ... } ... //用法如 URI uri = new URI("http","username:program-dog","program-dog.blogspot.com","/","","");
我们至少有7个参数,如果要满足各种需求的组合,恐怕总共要提供∑(C^7^~i~)(i=1~7)种构造函数,显然不现实。然而,
URIBuilder既可以造出一个
不可变的URI,又可以兼顾N种参数。
URIBuilder可以这样用:
// http://www.google.com/search?q=编程狗的博客&btnG=Google+Search&aq=f&oq= URI uri = new URIBuilder() .setScheme("http") .setHost("www.google.com") .setPath("/search") .setParameter("q", "编程狗的博客") .setParameter("btnG", "Google Search") .setParameter("aq", "f") .setParameter("oq", "") .build();
URIBuilder正是采用了Builder Pattern(建造者模式)。等号右边实际上是一行,先创建一个
URIBuilder对象实例,调用实例的setScheme方法,此方法顺便返回
URIBuilder对象实例,刚刚返回的这个实例调用setHost方法,...,最后一个返回的
URIBuilder对象实例调用build方法,返回URI对象。它是如何实现的呢?
原来的URI类的set方法的基础上,添加一个返回值,返回
URIBuilder自己就够了:
class URIBuilder{ public URIBuilder setScheme(String scheme){ ... return this; } public URIBuilder setHost(String host){ ... return this; } public URIBuilder setPath(String path){ ... return this; } //built 方法,把参数拼接,然后返回一个URI类 public URI built(){ ... return uri; } }
由于
URIBuilder每次都返回它自己,所以可以连续的执行 set方法,最后通过built方法返回URI类。
结束
到此为止,一个简单的URI类的写法已经介绍完毕了。我们还是尽量把URI写成类对象,并使它不可变,并且提供相应的Builder。
相关文章推荐
- Java网络编程(三) - Spring MVC高级特性
- 安卓简单技术-判断手机连接的是wifi还是数据流量
- 初学CentOS——压缩包、RPM包与网络命令基本
- TCP 三次握手
- openstack 网络发展简史
- openstack 网络发展简史
- openstack 网络发展简史
- kvm性能优化方案---cpu/内存/磁盘/网络
- openstack 网络架构 nova-network + neutron
- TCP/IP传输层,你懂多少?
- 家庭网络方案分享
- android中的网络解析xml,json,html框架
- 毕加索的艺术——Picasso,一个强大的Android图片下载缓存库,OkHttpUtils的使用,二次封装PicassoUtils实现微信精选
- 毕加索的艺术——Picasso,一个强大的Android图片下载缓存库,OkHttpUtils的使用,二次封装PicassoUtils实现微信精选
- Python的网络编程库Gevent的安装及使用技巧
- ios扩展http服务,将iphone做小型的http服务器
- Visualizing MNIST 降维探索
- http-关于application/x-www-form-urlencoded等字符编码的解释说明
- android之网络操作(1)
- EntityFramework.SqlServer.dll 中发生 其他信息: 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: Named Pipes Provider, error: 40 - 无法打开到 SQL Server 的连接)