zoukankan      html  css  js  c++  java
  • 如何写一个HttpClient[1]——URI的处理

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

    在翻阅apache的http client的代码的时候,看到org.apache.http.client.utils.URIBuilder.java的写法,感觉甚妙。特意分析一下源码,并且对比几种不同的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的可能换成httpwww.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){
    	...
    }
    

    这三个方法分别用来设置schemehostpath。为了叙述方便,没有对参数进行检查。仅仅提供这三个设置参数的方法是不能过实现置换的,因为对于传入的URI,必须先分割schemehostpath三部分。当然,我们可以的再添加一个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个参数,如果要满足各种需求的组合,恐怕总共要提供∑(C7i)(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。



    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。


    本文地址:https://program-dog.blogspot.com/2016/06/HowToWriteAHttpClientAboutURI.html


  • 相关阅读:
    springMVC上传文件简单案例
    java监听器、定时器的使用
    javaweb的web.xml配置说明,初始化过程
    Linux下解决高并发socket最大连接数限制,tcp默认1024个连接
    tsung压力测试——Tsung测试统计报告说明【转】
    tsung压力测试——tcp测试tsung.xml配置模版说明
    tsung压力测试——安装
    Java同步锁——lock与synchronized 的区别【转】
    Java集合——HashMap,HashTable,ConcurrentHashMap区别
    SpringMVC源码情操陶冶-FreeMarker之web配置
  • 原文地址:https://www.cnblogs.com/program-dog/p/5613010.html
Copyright © 2011-2022 走看看