您的位置:首页 > 理论基础 > 计算机网络

如何写一个HttpClient[1]——URI的处理

2016-06-24 08:54 323 查看

如何写一个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。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: