httpcore和httpclient的源码一点点(1)

因为需要重写自己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进行输出,没有乱码问题。

    @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呢?还是很期待的。
夜深了,学校断网了,明天再发帖吧。

by 徐建海
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值