• 自己动手写Web容器之TomJetty之三:掀起请求盖头来


    传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229

           前面我们对于实现TomJetty做了一些知识铺垫和复习,息知了HTTP请求的头部的组成元素。目前的TomJetty服务器已经能够成功启动,可是请求一旦过来却又看不懂^_^。所以本文就来解析HTTP请求头,剖析它的各部分。让TomJetty服务器能够明白它的意图。

    1HTTP请求头解析

    (1)编写一个RequestHeader类,用户封装请求头对象。

    package cn.lynn.tomjetty;
    
    import java.util.HashMap;
    
    /**
     * 封装请求头
     * @author lynnli1229
     */
    public class RequestHeader {
    
        private String method;
        private String url;
        private String protocal;
        private String accept;
        private String accept_language;
        private String user_agent;
        private String accept_encoding;
        private String ip;
        private String port;
        private String connection;
        private String cookie;
        
        // 存放请求头键值对
        private HashMap<String, String> map;
        // 存放请求头文本
        private String txt;
    
        // 省略getter()和setter()方法
    
        @Override
        public String toString() {
            return "RequestHeader [" + "\n"
                + method + " " + url + " " + protocal + "\n"
                + "Accept: " + accept + "\n"
                + "Accept-Language: " + accept_language + "\n"
                + "User-Agent: " + user_agent + "\n"
                + "Accept-Encoding: " + accept_encoding + "\n"
                + "Host: " + ip + ":" + port + "\n"
                + "Connection: " + connection + "\n"
                + "Cookie: " + cookie + "\n"
                + "]";
        }
    }
    

    (2)设计一个IRequestHeaderParser接口,并声明parse()方法,用于解析请求头文本内容。

    package cn.lynn.tomjetty;
    
    public interface IReqestHeaderParser {
    
        public RequestHeader parse(String txt) throws Exception;
    
    }

    (3)提供IRequestHeaderParser接口的实现类RequestHeaderParserImpl,用于执行解析操作。注意一下,我们是以IE浏览器请求头为例,其他版本浏览器请求头的参数顺序会有变动,但整体差别不大。

    package cn.lynn.tomjetty;
    
    import java.util.HashMap;
    
    public class RequestHeaderParserImpl implements IReqestHeaderParser {
    
        /**
         * 解析HTTP请求头
         */
        public RequestHeader parse(String txt) throws Exception {
            RequestHeader header = new RequestHeader();
            header.setTxt(txt);
    
            // 截取请求头第一行
            String firstLine = txt.substring(0, txt.indexOf("\n"));
            String method = firstLine.substring(0, firstLine.indexOf(" "));
            String url = firstLine.substring(firstLine.indexOf(" ") + 1, firstLine.lastIndexOf(" "));
            String protocal = firstLine.substring(firstLine.lastIndexOf(" ") + 1, firstLine.length());
            
            header.setMethod(method);// 获取Accept参数值,存放到RequestHeader对象当中
            header.setUrl(url);// 获取Accept参数值,存放到RequestHeader对象当中
            header.setProtocal(protocal);// 获取Accept参数值,存放到RequestHeader对象当中
            
            String[] lines = txt.split("\n");
            HashMap<String, String> map = new HashMap<String, String>();
            // 从请求头第二行开始分隔,因为第一行没有冒号
            for (int i = 1; i < lines.length; i++) {
                String[] result = lines[i].split(": ");
                map.put(result[0], (result.length <= 1) ? "" : result[1].replace('\n', ' ').trim());
            }
            header.setMap(map);
            header.setAccept(map.get("Accept")); // 获取Accept参数值,存放到RequestHeader对象当中
            header.setAccept_language(map.get("Accept-Language")); // 获取Accept-Language参数值,存放到RequestHeader对象当中
            header.setUser_agent(map.get("User-Agent")); // 获取User-Agent参数值,存放到RequestHeader对象当中
            header.setAccept_encoding(map.get("Accept-Encoding")); // 获取Accept-Encoding参数值,存放到RequestHeader对象当中
            header.setIp(map.get("Host").split(":")[0]); // 获取Host参数的IP参数值,存放到RequestHeader对象当中
            header.setPort(map.get("Host").split(":")[1]); // 获取Host参数的Port参数值,存放到RequestHeader对象当中
            header.setConnection(map.get("Connection")); // 获取Connection参数值,存放到RequestHeader对象当中
            header.setCookie(map.get("Cookie")); // 获取Cookie参数值,存放到RequestHeader对象当中
    
            return header;
        }
    
    }

    (4)在TomJetty类的run()方法中加入如下代码,用于将解析请求头的结果打印到控制台上。

    try {
        InputStream in = socket.getInputStream(); // 获取客户端发送的字节流
        OutputStream out = socket.getOutputStream(); // 获取服务端响应的字节流
        byte[] b = new byte[1024 * 1024]; // 设置字节缓冲区
        in.read(b); // 读取客户端字节流(字节流的请求头)
        String txt = new String(b).trim(); // 将请求头封装成String,准备交给解析器解析
        IReqestHeaderParser parser = (IReqestHeaderParser) Class.forName(TomJettyUtil.getValue("tomjetty.requestheader.class"))
            .newInstance(); // 使用工厂设计模式从tomjetty.config中加载请求头解析器的实例
        RequestHeader header = parser.parse(txt); // 终于可以解析了
        System.out.println(header);
    } catch (Exception e) {
        e.printStackTrace();
    }

    2解析效果展示


            在IE浏览器中输入上述地址后,控制台打印如下:

    RequestHeader [
    GET /hello.jsp HTTP/1.1
    Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/QVOD, application/QVOD, */*
    Accept-Language: zh-cn
    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; KB974488)
    Accept-Encoding: gzip, deflate
    Host: 127.0.0.1:9527
    Connection: Keep-Alive
    Cookie: null
    ]

            写到这里,我们终于完成了对HTTP请求头的解析操作,感觉代码比预想的要多,其中字符串的拆分是关键,其他也就没什么了。OK!现在的TomJetty已经能够读懂请求的内容了,接下来就要着手为该请求提供服务了。可是服务的方式有很多种,其中响应静态页面请求就是很基本的一种。所以,在接下来的一节中我们将处理TomJetty服务器响应静态网页请求的问题。


  • 相关阅读:
    [如何构建自己的轮式移动机器人系统·从入门到放弃]机器人底层篇
    Readme.txt
    [MATLAB&SIMULINK] 如何提取并处理Simscape Power System 中powergui的谐波分析数据
    记录2016年12月11日
    [深度强化学习] blog翻译使用Keras与Gym仿真环境进行深度Q学习(DQL)
    使用PARL与Gym仿真环境进行深度Q学习(DQL)
    Telerik控件使用Expression_DarkTheme后引发Combobx下拉问题
    [Win系统][临时方案]系统任务管理器不能使用临时性解决方案
    [Visual Studio]重置开发环境
    WPF中使用DataGrid后,里面的Button的Command不响应的问题
  • 原文地址:https://www.cnblogs.com/innosight/p/3271185.html
Copyright © 2020-2023  润新知