跟我一起动手实现Tomcat(一):实现静态Web服务器
2017-12-30 16:53
525 查看
前言
最近笔者读了《深入剖析tomcat》这本书(原作:《how tomcat works》), 发现该书简单易读,每个章节循序渐进的讲解了tomcat的原理, 本文为记录第一章的知识点以及源码实现(造轮子)。
如何实现
HTTP协议就是咱们web服务器与浏览器交互的协议,具体的知识点以及背景本文就不再累述。那么举一个简单的例子就好:- 在浏览器输入http://www.baidu.com按下回车键。
- 浏览器大概发送了以下的http请求到百度的服务器中:
GET /index.html HTTP/1.1 Host: www.baidu.com ...
百度web服务器在接收到我们的请求的时候,找到对应的服务器资源并相应:
HTTP/1.1 200 OK ... <html> <head> <title>百度一下你就知道</title> </head> <body> .... </body> </html>
那么其实通过上面的例子我们可以发现,静态(这里指的是html/图片/css等)web服务器的实现也是比较简单的:
用户请求-->服务器寻找相应的资源-->服务器输出对应的资源-->浏览器展示给用户
代码实现
在这里使用java socket api 实现简单的静态web服务器。
新建一个main方法,核心伪代码如下:
//开启socket server 8080端口监听. ServerSocket server = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1")); try (Socket accept = serverSocket.accept(); InputStream inputStream = accept.getInputStream(); OutputStream outputStream = accept.getOutputStream()) { //解析用户的请求 Request request = new Request(); request.setRequestStream(inputStream); request.parseRequest(); //生成响应对象并响应静态资源 Response resp = new Response(outputStream, request); resp.accessStaticResources(); } catch (IOException e) { LOGGER.war 4000 n("catch from user request.",e); } //关闭服务器 serverSocket.close();
Request 对象
主要功能:将用户请求(socket的inputStream流)解析为字符串,提取请求中的URI
解析字符串代码如下:
StringBuilder requestStr = new StringBuilder(); int i; //new 一个 byte缓冲数组 byte[] buffer = ArrayUtil.generatorCache(); try { i = inputStream.read(buffer); } catch (IOException e) { e.printStackTrace(); i = -1; } //将读取到的byte转为String for (int j = 0; j < i; j++) { requestStr.append((char) buffer[j]); } //解析请求的字符串,提取请求的URI this.parseURI(requestStr.toString());
那么请求的信息被我们解析成字符串了,我们怎么知道他想请求什么静态资源呢?
那我们把解析字符串打印一下:
System.out.println(requestStr.toString());
GET /index.html HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
可以很明显的看到,加粗的地方就是我们要提取的URI,那么怎么提取呢?细心的我们发现了,/index.html 这段字符串前后都有一个空格!行,那我们可以直接用String的indexOf方法解析,参考代码如下:
// 获取/index.html 前面的那个空格索引 int oneSpace = requestStr.indexOf(" "); //获取/index.html 后面的那个空格索引 int twoSpace = requestStr.indexOf(" ", oneSpace + 1); //截取获得用户请求URI uri = requestStr.substring(oneSpace + 1, twoSpace);
Response 对象
上面Request对象已经把用户想请求的资源解析出来了,那么Response的功能就是找到这个文件, 使用Socket的outputStream把文件作为字节流输出给浏览器,就可以将我们的HTML显示给用户啦~
那么这个项目我们的静态文件放在那里呢?来看看我们的项目结构:
-main -java java代码 -resources -webroot 存放我们静态资源的文件夹
因为是只使用MAVEN构建项目,我们也没使用Spring等框架,如何定位到webroot这个文件夹呢?参考了网上的代码:
String WEB_PROJECT_ROOT = HttpServer.class.getClassLoader().getResource("webroot").getFile().substring(1);
前面的疑惑都解决了,接下来我们就直接把对应的文件找到给写回去就完事了~
伪码如下:
//根据请求URI找到用户对应请求的资源文件 File staticResource = new File(HttpServer.WEB_PROJECT_ROOT + request.getUri()); //资源存在 if (staticResource.exists() && staticResource.isFile()) { outputStream.write(this.responseToByte(200,"OK")); write(staticResource); //资源不存在,使用默认的404返回 } else { staticResource = new File(HttpServer.WEB_PROJECT_ROOT + "/404.html"); outputStream.write(this.responseToByte(404,"file not found")); write(staticResource); }
其中,responseToByte()这个方法只负责将响应行输出:
HTTP/1.1 200 OK
资源不存在时咱们就输出:
HTTP/1.1 404 file not found
write()方法也很简单,将传入的file对象转成流并使用socket的outputStream输出
try (FileInputStream fis = new FileInputStream(file)) { byte[] cache = new byte[1024]; int read; while ((read = fis.read(cache, 0, 1024)) != -1) { outputStream.write(cache, 0, read); } }
看看效果
运行main方法,打开我们的浏览器输出127.0.0.1/index.html按下回车,可以看到结果如图:试试随便输入一个不存在的资源:
按下F12看看Http请求和响应分别是怎样的:
请求: GET /abc.html HTTP/1.1 Host: 127.0.0.1:8080 其他请求头忽略... 响应: HTTP/1.1 404 file not found <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>404 not found!</title> </head> <body> <h1>请求页面不存在!</h1> </body> </html>
到这里,咱们的Tomcat 1.0 web服务器就已经开发完成啦(滑稽脸),已经可以实现简单的html和css、图片等资源的访问等功能,下一章咱们来实现以下简单的Servlet容器功能开发(ZHONG TOU XI)敬请期待~
PS:本章源码已上传github SimpleTomcat
相关文章推荐
- apache整合tomcat实现web服务器的动静态资源的分离解析
- Python实现web静态服务器
- 启动Linux 的时候实现oracle数据库与Tomcat web服务器与操作系统一同关闭与启动
- 三、Nginx+Tomcat实现Web服务器的负载均衡
- Tomcat结合Apache、Nginx实现高性能的web服务器
- 【原创】自己动手实现静态资源服务器
- Linux下安装MyEclipse和Tomcat服务器详解,以及我安装过程中所出现的问题以及解决办法,并实现一个web小程序
- apache整合tomcat实现web服务器解析
- 自己动手实现web服务器1.0版本-返回固定页面
- Tomcat-002-让简单的web服务器同时提供静态资源和servlet
- 自己动手写web服务器四(web服务器是如何通过压缩数据,web服务器的gzip模块的实现)
- 关于使用nat123软件实现外网访问内网的部署在Tomcat服务器中的Java Web项目
- 自己动手写web服务器四(web服务器是如何通过压缩数据,web服务器的gzip模块的实现)
- jsp+servlet实现大型文件下载(tomcat服务器),将自己今天做的和大家一起分享
- 自己动手写web服务器四(web服务器是如何通过压缩数据,web服务器的gzip模块的实现)
- 【Linux运维-集群技术进阶】Nginx+Tomcat实现Web服务器的负载均衡
- Nodejs实现web静态服务器对多媒体文件的支持
- 【原创】分布式之缓存击穿 【原创】自己动手实现静态资源服务器 【原创】自己动手实现JDK动态代理
- 自己动手实现一个WEB服务器