博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[置顶] 野生Web容器之TomJetty之掀起你的盖头来
阅读量:6082 次
发布时间:2019-06-20

本文共 6399 字,大约阅读时间需要 21 分钟。

        上文我们对于实现这个野生Web容器做了一些知识铺垫和复习,息知了HTTP请求的头部的组成元素,本文我们主要讲解如何在代码中去解析它的各个部分,掀起盖头来,给哥笑一个^_^。在这之前,我们需要建立服务器,把框架搭建起来。

一、服务器建立

1.新建一个名为TomJetty的Java工程。

2.在工程src目录下新建一个tomjetty.config文件,用于提供服务器配置参数。

tomjetty.port=8080tomjetty.requestheader.class=cn.lynn.tomjetty.RequestHeaderParserImpl

3.编写一个工具类TomJettyUtil,用于程序读取配置参数值。

package cn.lynn.tomjetty;import java.io.IOException;import java.util.Properties;public class TomJettyUtil {    private static Properties props = new Properties();        static {        try {            props.load(TomJettyUtil.class.getClassLoader().getResourceAsStream("tomjetty.config"));        } catch (IOException e) {            e.printStackTrace();            System.exit(0);        }    }        public static String getValue(String key) {        return props.getProperty(key);    }}

4.编写一个TomJetty类继承于Thread类,用于封装服务器对象

public class TomJetty extends Thread {    private static ServerSocket server;    private Socket socket;    public TomJetty(Socket socket) {        this.socket = socket;    }        ...}

5.为TomJetty类提供openServer()和closeServer()方法,用户打开和关闭服务器。

public static void openServer() throws Exception {        server = new ServerSocket(Integer.parseInt(TomJettyUtil                .getValue("tomjetty.port")));        while (true) {            new TomJetty(server.accept()).start();        }    }public static void closeServer() throws Exception {    if (server != null) {        if (!server.isClosed()) {            server.close();        }    }}

6.编写一个StartTomJetty类,用于开启服务器。

package cn.lynn.tomjetty;public class StartTomJetty {    public static void main(String[] args) {        try {            TomJetty.openServer();        } catch (Exception e) {            try {                TomJetty.closeServer();            } catch (Exception e1) {                e1.printStackTrace();            }        }    }}

        这样一来,服务器就能运行了。当然,它什么也不会做。因为我们在run()方法中没有进行任何操作^_^。不要急,休息一下,后面就会讲到,另外代码部分也会随着章节的深入而重构。

二、HTTP请求头解析

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
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
map = new HashMap
(); // 从请求头第二行开始分隔,因为第一行没有冒号 for (int i = 1; i < lines.length; i++) { map.put(lines[i].split(": ")[0], lines[i].split(": ")[1]); } 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();}

三、运行效果展示

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

RequestHeader [GET /hello.jsp HTTP/1.1Accept: 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-cnUser-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; KB974488)Accept-Encoding: gzip, deflateHost: 127.0.0.1:8080Connection: Keep-AliveCookie: null]

        写到这里,我们终于完成了对HTTP请求头的解析操作,代码比预想的要多,其中字符串的拆分是关键,其他也没什么了。OK!下一站将是构建静态页面。

你可能感兴趣的文章
系统架构简单图解
查看>>
浅谈加密技术
查看>>
centOS7下安装GUI图形界面
查看>>
一张图透析阿里云API应用创新大赛
查看>>
sql重复行求和
查看>>
Microsoft Dynamics CRM 2013 and 2011 Update Rollups and Service Packs
查看>>
transient的理解
查看>>
python中if __name__ == '__main__': 介绍
查看>>
HackRF实现无线门铃信号分析重放
查看>>
Windows源码安装PyTorch 0.4
查看>>
AI开发者福音!阿里云推出国内首个基于英伟达NGC的GPU优化容器
查看>>
CentOS6安装和配置rsync
查看>>
在真机里安装 ubuntu 14.04和一些常用的软件(二)
查看>>
python2.6升级到2.7
查看>>
Unity SLua 如何调用Unity中C#方法
查看>>
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
查看>>
linux基础命令-查看系统状态-free -m以及top命令详解
查看>>
动态代理
查看>>
批量删除redis key
查看>>
被嫌弃的eval和with
查看>>