httpcore和httpclient的源码一点点(1)
2015-11-01 08:32
806 查看
因为需要重写自己github上以前的项目(“eat my dog food”),进行一次彻底的技术上的”寻根究底”.
项目中使用了爬虫获取数据,后台接入了多个爬虫的数据源,这前写这些爬虫的时候,有大量的逻辑是重复的,于是,第一件事情便是抽象出一个简单的java爬虫框架(后期可以使用go和python),采用spring类似的机制: 获取配置文件,扫描项目,获取注解,整个框架只需要用户处理response的页面(html的解析、url抽取,然后决定是否进行存储,其中,url可以扔进调度器, 用户也可以自定义拦截插件) , 整体逻辑可能倾向scrapy。
众所周知,java se自身并没有完整的http包(只有简单的java.net包), j2ee的javax有相关实现(记得 javax.servlet.http.HTTPServletRequest和javax.servlet.http.HTTPServletResponse),如果看过jetty和tomcat容器你会发现他们都有自己的实现.而在其他的语言中,python有httplib包,go有http包,在实际的java开发过程中,用的最多的就是httpclient了吧,除了android多了一个选择。
httpclient是在httpcore上进行开发的,于是先看httpcore。
httpcore中,分成了如下几个包 :
entity : 响应体和请求体的抽象, buffered bytearray file inputstream类型的实现,序列化化和反序列化 -> 中规中矩
io -> messe的读取和写入(官方注释给出了data source 和 data sink的短语,有点flume的意思,这里就不误导了),还提供了两个类似jdk的InputStream和OutputStream的实现 : SessionInoutStream和SessionOutputStream, 区别在于提供了写入和读取行(readLine和writeLine的方法),别被Session的前缀欺骗了,还有一个HttpTransportMetrics类
message->提供 requestLine statusLine header HTTPRequest HTTPResponse的实现,有iterator迭代器、(value/line)formatter格式化器、namevaluePair、LineParser解析器等
params->HTTPPrams、HTTPConnectionParams、HTTPProtocolParams这几个参数的类为主
protocol-> HTTPContext、HTTPProcessor(合并了HTTPRequestProcessor和HTTPResponseProcessor) , Rquest相关的处理器(useragent、TargetHost、ExpectContinue、Date、Content、ConnControl、组合的列表->个人感觉命名Composite比List好), Response相关的处理器(ConnControl、Content、Date、Server、组合的列表->个人感觉命名Composite比List好), HTTP类中存放了常见的常量,有几个比较有意思的东西 : HTTPRequestexecutor(客户端使用的阻塞io的 HTTP 协议处理,根据请求获取响应)、HttpRequestHandler(根据request产生response的接口:服务器端使用)、HttpRequestHandlerResolver(维护HttpRequesthandler的管理的接口)、HttpRequestHandlerRegistry(相应的实现)和UriPatternMatcher(内部使用map实现注册、注销、查询)
util->常用的工具
imp - >entity、io的实现, io 还是比较有趣的
直接实现 :http协议的常见抽象(看过jetty实现的同学会很清楚),像HTTPEntry、 HTTPRequest 、HTTPResponse等,都是根据rfc 2613等文件写的,没有太多的惊艳的地方
测试 :
官方的example目录中的代码在请求中文网站会有问题,问题在EntityUtil上,我后面给成了BufferedReader进行输出,没有乱码问题。
从上面可以看到,最大的特点 : httpproc.addInterceptor, 添加拦截器,是不是有点回到struts的赶脚,别冲动,这里讨论的是爬虫, 拦截器Interceptor 可以作为爬虫的预处理器middleware、ProcessChain,这些只是名字上的差异,本质就是针对404、5xx、3xx redirect 、auth、useragent 等情况进行处理,貌似浮出了爬虫的影子。
而且,除此之外,还提供了nio的实现,还是很贴心的,准备放入项目中进行测试。会不会跟新到aio呢?还是很期待的。
夜深了,学校断网了,明天再发帖吧。
[align=right]by 徐建海[/align]
项目中使用了爬虫获取数据,后台接入了多个爬虫的数据源,这前写这些爬虫的时候,有大量的逻辑是重复的,于是,第一件事情便是抽象出一个简单的java爬虫框架(后期可以使用go和python),采用spring类似的机制: 获取配置文件,扫描项目,获取注解,整个框架只需要用户处理response的页面(html的解析、url抽取,然后决定是否进行存储,其中,url可以扔进调度器, 用户也可以自定义拦截插件) , 整体逻辑可能倾向scrapy。
众所周知,java se自身并没有完整的http包(只有简单的java.net包), j2ee的javax有相关实现(记得 javax.servlet.http.HTTPServletRequest和javax.servlet.http.HTTPServletResponse),如果看过jetty和tomcat容器你会发现他们都有自己的实现.而在其他的语言中,python有httplib包,go有http包,在实际的java开发过程中,用的最多的就是httpclient了吧,除了android多了一个选择。
httpclient是在httpcore上进行开发的,于是先看httpcore。
httpcore中,分成了如下几个包 :
entity : 响应体和请求体的抽象, buffered bytearray file inputstream类型的实现,序列化化和反序列化 -> 中规中矩
io -> messe的读取和写入(官方注释给出了data source 和 data sink的短语,有点flume的意思,这里就不误导了),还提供了两个类似jdk的InputStream和OutputStream的实现 : SessionInoutStream和SessionOutputStream, 区别在于提供了写入和读取行(readLine和writeLine的方法),别被Session的前缀欺骗了,还有一个HttpTransportMetrics类
message->提供 requestLine statusLine header HTTPRequest HTTPResponse的实现,有iterator迭代器、(value/line)formatter格式化器、namevaluePair、LineParser解析器等
params->HTTPPrams、HTTPConnectionParams、HTTPProtocolParams这几个参数的类为主
protocol-> HTTPContext、HTTPProcessor(合并了HTTPRequestProcessor和HTTPResponseProcessor) , Rquest相关的处理器(useragent、TargetHost、ExpectContinue、Date、Content、ConnControl、组合的列表->个人感觉命名Composite比List好), Response相关的处理器(ConnControl、Content、Date、Server、组合的列表->个人感觉命名Composite比List好), HTTP类中存放了常见的常量,有几个比较有意思的东西 : HTTPRequestexecutor(客户端使用的阻塞io的 HTTP 协议处理,根据请求获取响应)、HttpRequestHandler(根据request产生response的接口:服务器端使用)、HttpRequestHandlerResolver(维护HttpRequesthandler的管理的接口)、HttpRequestHandlerRegistry(相应的实现)和UriPatternMatcher(内部使用map实现注册、注销、查询)
util->常用的工具
imp - >entity、io的实现, io 还是比较有趣的
直接实现 :http协议的常见抽象(看过jetty实现的同学会很清楚),像HTTPEntry、 HTTPRequest 、HTTPResponse等,都是根据rfc 2613等文件写的,没有太多的惊艳的地方
测试 :
官方的example目录中的代码在请求中文网站会有问题,问题在EntityUtil上,我后面给成了BufferedReader进行输出,没有乱码问题。
@Test public void testMethod(){ // params有点怪怪的 // System.out.println("开始了"); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, "UTF-8"); HttpProtocolParams.setUserAgent(params, "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"); HttpProtocolParams.setUseExpectContinue(params, true); // 可以添加自定义的处理器 BasicHttpProcessor httpproc = new BasicHttpProcessor(); // Required protocol interceptors httpproc.addInterceptor(new RequestContent()); httpproc.addInterceptor(new RequestTargetHost()); // Recommended protocol interceptors httpproc.addInterceptor(new RequestConnControl()); // httpproc.addInterceptor(new RequestUserAgent()); httpproc.addInterceptor(new RequestExpectContinue()); HttpRequestExecutor httpexecutor = new HttpRequestExecutor(); HttpContext context = new BasicHttpContext(null); // 需要存放ip地址, HttpHost host = new HttpHost("http://51voa.com", 80); HttpHost host = new HttpHost("110.76.43.78",80); DefaultHttpClientConnection conn = new DefaultHttpClientConnection(); ConnectionReuseStrategy connStrategy = new DefaultConnectionReuseStrategy(); context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn); context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host); try { // 第一种是官方的,第二种竟没有resolveURL的类似解决方案 // String[] targets = { // "/", // "/servlets-examples/servlet/RequestInfoExample", // "/somewhere%20in%20pampa"}; // String[] targets = { // "/", // "/VOA_Standard_English/microscope-brings-tiny-worlds-closer-researchers-66090.html", // "/Technology_Report_1.html"}; String[] targets = { "http://www.51voa.com/VOA_Standard_1.html", "http://www.51voa.com/VOA_Standard_English/microscope-brings-tiny-worlds-closer-researchers-66090.html", "http://www.51voa.com/Technology_Report_1.html"}; for (int i = 0; i < targets.length; i++) { if (!conn.isOpen()) { Socket socket = new Socket(host.getHostName(), host.getPort()); conn.bind(socket, params); } BasicHttpRequest request = new BasicHttpRequest("GET", targets[i]); System.out.println(">> Request URI: " + request.getRequestLine().getUri()); request.setParams(params); httpexecutor.preProcess(request, httpproc, context); HttpResponse response = httpexecutor.execute(request, conn, context); response.setParams(params); httpexecutor.postProcess(response, httpproc, context); System.out.println("<< Response: " + response.getStatusLine()); // 这里需要进行处理 BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); String str = null; while((str=reader.readLine())!=null){ System.out.println(" line => " + str); } // 使用这个方法会导致 乱码 // System.out.println(EntityUtils.toString(response.getEntity())); System.out.println("=============="); if (!connStrategy.keepAlive(response, context)) { conn.close(); } else { System.out.println("Connection kept alive..."); } } }catch(Exception ex){ }finally { System.out.println("结束"); try{ conn.close(); }catch(Exception e){ } } }
从上面可以看到,最大的特点 : httpproc.addInterceptor, 添加拦截器,是不是有点回到struts的赶脚,别冲动,这里讨论的是爬虫, 拦截器Interceptor 可以作为爬虫的预处理器middleware、ProcessChain,这些只是名字上的差异,本质就是针对404、5xx、3xx redirect 、auth、useragent 等情况进行处理,貌似浮出了爬虫的影子。
而且,除此之外,还提供了nio的实现,还是很贴心的,准备放入项目中进行测试。会不会跟新到aio呢?还是很期待的。
夜深了,学校断网了,明天再发帖吧。
[align=right]by 徐建海[/align]
相关文章推荐
- 从源码安装Mysql/Percona 5.5
- 浅析Ruby的源代码布局及其编程风格
- asp.net 抓取网页源码三种实现方法
- JS小游戏之仙剑翻牌源码详解
- JS小游戏之宇宙战机源码详解
- jQuery源码分析之jQuery中的循环技巧详解
- 本人自用的global.js库源码分享
- ASP.NET MVC Web API HttpClient简介
- java中原码、反码与补码的问题分析
- 使用httpclient实现免费的google翻译api
- PHP网页游戏学习之Xnova(ogame)源码解读(六)
- C#获取网页HTML源码实例
- PHP网页游戏学习之Xnova(ogame)源码解读(八)
- PHP网页游戏学习之Xnova(ogame)源码解读(四)
- PHP封装的HttpClient类用法实例
- JS小游戏之极速快跑源码详解
- JS小游戏之象棋暗棋源码详解
- android源码探索之定制android关机界面的方法
- Android 中HttpURLConnection与HttpClient使用的简单实例
- 基于Android设计模式之--SDK源码之策略模式的详解