如何写一个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的可能换成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个参数,如果要满足各种需求的组合,恐怕总共要提供∑(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
如何写一个HttpClient[1]——URI的处理的更多相关文章
- 如何写一个简单的http服务器
最近几天用C++写了一个简单的HTTP服务器,作为学习网络编程和Linux环境编程的练手项目,这篇文章记录我在写一个HTTP服务器过程中遇到的问题和学习到的知识. 服务器的源代码放在Github. H ...
- Java Web 开发利用Struts2+Spring+mybatis写一个用户登录界面以及简单的数据交互
框架的东西太复杂也难以讲通,直接上代码: 一.首先得配置环境 和导入必要的jar包 有一些重要的如下: Filter文件夹下的SafetyFilter.java model文件夹下的 Global ...
- 【Filter 不登陆无法访问】web项目中写一个过滤器实现用户不登陆,直接给链接,无法进入页面的功能
在web项目中写一个过滤器实现用户不登陆,直接给链接,无法进入页面,而重定向到登陆界面的功能. 项目是用springMVC+spring+hibernate实现 (和这个没有多大关系) 第一步: 首先 ...
- 【Filter 页面重定向循环】写一个过滤器造成的页面重定向循环的问题
今天做一个过滤器,碰上页面重定向循环的情况: 浏览器的访问路径是:http://192.168.16.104:8080/biologyInfo/login/login/login/login/logi ...
- 与众不同 windows phone (38) - 8.0 关联启动: 使用外部程序打开一个文件或URI, 关联指定的文件类型或协议
[源码下载] 与众不同 windows phone (38) - 8.0 关联启动: 使用外部程序打开一个文件或URI, 关联指定的文件类型或协议 作者:webabcd 介绍与众不同 windows ...
- (2)自己写一个简单的servle容器
自己写一个简单的servlet,能够跑一个简单的servlet,说明一下逻辑. 首先是写一个简单的servlet,这就关联到javax.servlet和javax.servlet.http这两个包的类 ...
- 用c++写一个 “hello,world” 的 FastCGI程序
原文:http://chriswu.me/blog/writing-hello-world-in-fcgi-with-c-plus-plus/ 上面的连接地址给出的是作者的原文地址. 另外一个作者稍微 ...
- 手动的写一个structs
为了更好的学习框架的运行机制,这里开始学习框架之前,介绍一个简单的自定义的框架. 需求: 登录:id:aaa,pwd:888登录成功之后,跳转到,index.jsp页面并显示,欢迎你,aaa 注册,页 ...
- 爬虫入门 手写一个Java爬虫
本文内容 涞源于 罗刚 老师的 书籍 << 自己动手写网络爬虫一书 >> ; 本文将介绍 1: 网络爬虫的是做什么的? 2: 手动写一个简单的网络爬虫; 1: 网络爬虫是做 ...
随机推荐
- 简明 Git 命令速查表(中文版)
原文引用地址:https://github.com/flyhigher139/Git-Cheat-Sheet/blob/master/Git%20Cheat%20Sheet-Zh.md在Github上 ...
- 【Scala】尾递归优化
以递归方式思考 递归通过灵巧的函数定义,告诉计算机做什么.在函数式编程中,随处可见递归思想的运用.下面给出几个递归函数的例子: object RecursiveExample extends App{ ...
- Google Gson 使用简介
http://www.cnblogs.com/haippy/archive/2012/05/20/2509329.html
- Google 云计算中的 GFS 体系结构
google 公司的很多业务具有数据量巨大的特点,为此,google 公司研发了云计算技术.google 云计 算结构中的 google 文件系统是其云计算技术中的三大法宝之一.本文主要介 ...
- localstorage 的属性改变问题
localstorage 得到的是对象,我们打算改对象的某个属性的值,方法是 通过临时变量对象得到,改变临时变量,然后把临时变量给localstorage的方法 var localS = windo ...
- 好看的IDE配色方案让代码看起来不再那么凶猛了
写这篇小文的初衷是,笔者是原教旨主义者,一直坚持用IDE默认的配色方案.另外也觉得网上黑色系的配色方案太过bling bling了.但今天尝试用新的配色方案后,兴奋地发现对代码的好感度大幅提升. 嗯, ...
- laravel Input Cokkie 的各种方法 超实用!!!
基本输入 Laravel使用一种简单的方式来访问用户提交的信息. 你可以用统一的方式来访问用户提交的信息,而不用为用户提交信息的方式操心. 获取一个用户提交的值 代码如下: $name = Input ...
- jdk(多版本)安装注意!
♣安装jdk和jre ♣jdk配置环境变量和测试 ♣安装多版本jdk和切换 ♣jdk下的jre和第二次安装的jre的区别 注意点: 1.jdk版本需要是64位 2.安装JDK 选择安装目录 安装过程中 ...
- Purfer Sequence
原文地址:http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/23/3278557.html 我们知道,一棵树可以用括号序列来表示,但是,一棵顶点 ...
- mongodb权限管理
说到mongodb就得先谈谈mongodb的用户组,和传统的关系型数据库不一样,mongodb并没有在创建应用时就要求创建权限管理组,所以类似于Robomongo这样的数据库可视化工具在创建conne ...
