从零手写实现 tomcat-10-static resource 静态资源文件

简介: 该文档记录了作者为理解Tomcat精髓,动手从零开始实现一个简化版Tomcat的过程。系列教程包括对web.xml的解析、基础的Socket实现、请求响应抽象、Servlet支持、线程池处理、WAR包解析及与SpringBoot集成等。文章以静态资源处理为例,介绍了如何接收HTTP请求,查找并返回文件内容,以及处理失败情况。代码示例展示了静态资源的分发逻辑。项目已开源,可在GitHub上访问[https://github.com/houbb/minicat](https://github.com/houbb/minicat)。

创作缘由

平时使用 tomcat 等 web 服务器不可谓不多,但是一直一知半解。

于是想着自己实现一个简单版本,学习一下 tomcat 的精髓。

系列教程

从零手写实现 apache Tomcat-01-入门介绍

从零手写实现 apache Tomcat-02-web.xml 入门详细介绍

从零手写实现 tomcat-03-基本的 socket 实现

从零手写实现 tomcat-04-请求和响应的抽象

从零手写实现 tomcat-05-servlet 处理支持

从零手写实现 tomcat-06-servlet bio/thread/nio/netty 池化处理

从零手写实现 tomcat-07-war 如何解析处理三方的 war 包?

从零手写实现 tomcat-08-tomcat 如何与 springboot 集成?

从零手写实现 tomcat-09-servlet 处理类

从零手写实现 tomcat-10-static resource 静态资源文件

从零手写实现 tomcat-11-filter 过滤器

从零手写实现 tomcat-12-listener 监听器

前言

静态资源文件都有啥?

在Tomcat中,静态文件通常指的是那些不需要服务器动态处理就可以直接返回给客户端的文件,比如HTML页面、CSS样式表、JavaScript脚本、图片等。

这些文件的内容是固定的,不会根据每个请求而改变。

举个板栗

处理静态文件请求的过程,可以比作一个小卖部的自动售货机:

  1. 请求静态文件:当顾客(客户端)想要一瓶饮料(请求静态文件),他们会向自动售货机(Tomcat服务器)投入硬币(发送HTTP请求)。

  2. 查找文件:自动售货机会检查库存(查找服务器上的文件系统),看看顾客想要的饮料(请求的文件)是否有货。

  3. 返回文件:如果饮料(文件)有货,自动售货机会将饮料(文件内容)直接推出(返回给客户端)。顾客拿到饮料就完成了购买。

  4. 处理失败:如果饮料(文件)缺货,自动售货机会告诉顾客并退回硬币(返回错误响应,如404 Not Found)。

下面是一个模拟的自动售货机处理顾客请求的步骤,用以比喻Tomcat处理静态文件请求的过程:

顾客投入硬币(客户端发送HTTP请求到Tomcat服务器)

    +------+      请求文件     +------+      查找文件
    | 顾客 |  -------------->| 售货机 |  <---+ 查找文件系统
    +------+                 +------+      |
                                |         |
    +------+      返回文件     +------+      |
    | 顾客 |  <--------------| 售货机 |  <---+ 文件存在
    +------+                 +------+      |
                                |         |
                                |         |
    +------+      处理失败     +------+      |
    | 顾客 |  <--------------| 售货机 |  <---+ 文件不存在
    +------+                 +------+      |
                                |
顾客拿到饮料(客户端接收到文件内容)

自己实现

相比 serlvet,这个就要简单的多。

但是我们还是要处理好统一的请求分发逻辑。

请求的分发

静态资源文件的处理

package com.github.houbb.minicat.support.request;

import com.github.houbb.heaven.util.io.FileUtil;
import com.github.houbb.log.integration.core.Log;
import com.github.houbb.log.integration.core.LogFactory;
import com.github.houbb.minicat.bs.MiniCatBootstrap;
import com.github.houbb.minicat.dto.IMiniCatRequest;
import com.github.houbb.minicat.dto.IMiniCatResponse;
import com.github.houbb.minicat.support.context.MiniCatContextConfig;
import com.github.houbb.minicat.util.InnerHttpUtil;
import com.github.houbb.minicat.util.InnerResourceUtil;

/**
 * 静态页面
 * @author 老马啸西风
 */
public class StaticHtmlRequestDispatcher implements IRequestDispatcher {
   

    private static final Log logger = LogFactory.getLog(StaticHtmlRequestDispatcher.class);

    public void dispatch(final IMiniCatRequest request,
                         final IMiniCatResponse response,
                         final MiniCatContextConfig config) {
   

        String absolutePath = InnerResourceUtil.buildFullPath(config.getBaseDir(), request.getUrl());
        String content = FileUtil.getFileContent(absolutePath);
        logger.info("[MiniCat] static html path: {}, content={}", absolutePath, content);
        String html = InnerHttpUtil.http200Resp(content);
        response.write(html);
    }

}

调用入口

在接收到请求,根据请求地址统一分发处理。

不同分发逻辑的匹配

package com.github.houbb.minicat.support.request;

/**
 * 请求分发管理器
 *
 * @since 0.3.0
 */
public class RequestDispatcherManager implements IRequestDispatcher {
   

    private static final Log logger = LogFactory.getLog(RequestDispatcherManager.class);

    private final IRequestDispatcher emptyRequestDispatcher = new EmptyRequestDispatcher();
    private final IRequestDispatcher servletRequestDispatcher = new ServletRequestDispatcher();
    private final IRequestDispatcher staticHtmlRequestDispatcher = new StaticHtmlRequestDispatcher();

    @Override
    public void dispatch(final IMiniCatRequest request,
                         final IMiniCatResponse response,
                         final MiniCatContextConfig config) {
   
        final IServletManager servletManager = config.getServletManager();


        // 判断文件是否存在
        String requestUrl = request.getUrl();

        // 获取请求分发
        final IRequestDispatcher requestDispatcher = getRequestDispatcher(requestUrl);

        // 正式分发
        requestDispatcher.dispatch(request, response, config);
    }

    private IRequestDispatcher getRequestDispatcher(String requestUrl) {
   
        if (StringUtil.isEmpty(requestUrl)) {
   
            return emptyRequestDispatcher;
        } else {
   
            if (requestUrl.endsWith(".html")) {
   
                return staticHtmlRequestDispatcher;
            } else {
   
                return servletRequestDispatcher;
            }
        }
    }

}

调用逻辑:

class MiniCatServerHandler extends ChannelInboundHandlerAdapter {
   

    // ... 省略

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   
        // ... 省略

        // 分发调用
        requestDispatcher.dispatch(request, response, miniCatContextConfig);

        // ... 省略
    }

    // ... 省略
}

这样,一个简单的静态资源文件处理流程就实现了。

开源地址

 /\_/\  
( o.o ) 
 > ^ <

mini-cat 是简易版本的 tomcat 实现。别称【嗅虎】(心有猛虎,轻嗅蔷薇。)

开源地址:https://github.com/houbb/minicat

相关文章
|
2月前
|
负载均衡 前端开发 应用服务中间件
Nginx+Tomcat负载均衡配置_nginx做tomcat的负载均衡成功,但tomcat的css文件400
Nginx+Tomcat负载均衡配置_nginx做tomcat的负载均衡成功,但tomcat的css文件400
|
2月前
|
负载均衡 前端开发 应用服务中间件
Nginx+Tomcat负载均衡配置_nginx做tomcat的负载均衡成功,但tomcat的css文件400(2)
Nginx+Tomcat负载均衡配置_nginx做tomcat的负载均衡成功,但tomcat的css文件400(2)
|
2月前
|
Java 应用服务中间件
解决tomcat启动报错:无法在web.xml或使用此应用程序部署的jar文件中解析绝对的url [http:java.sun.com/jsp/jstl/core]
解决tomcat启动报错:无法在web.xml或使用此应用程序部署的jar文件中解析绝对的url [http:java.sun.com/jsp/jstl/core]
861 1
|
11月前
|
SQL 关系型数据库 MySQL
CentOS部署JAVA程序、安装Tomcat以及安装导入mysql文件的方法
CentOS部署JAVA程序、安装Tomcat以及安装导入mysql文件的方法
|
2月前
|
Java 应用服务中间件
Tomcat 报错:The origin server did not find a current representation for the target resource
Tomcat 报错:The origin server did not find a current representation for the target resource
46 1
|
8月前
|
Unix 应用服务中间件 Linux
Tomcat清理日志文件无法立即释放磁盘空间
Tomcat清理日志文件无法立即释放磁盘空间
|
Java 应用服务中间件
用IDEA创建servlet文件并用Tomcat运行
用IDEA创建servlet文件并用Tomcat运行
157 0
|
安全 Java 应用服务中间件
tomcat的put方法任意文件写入漏洞浅谈
tomcat的put方法任意文件写入漏洞浅谈
253 0
|
安全 Java 应用服务中间件
CVE-2017-12615 Tomcat PUT方法任意写文件漏洞
CVE-2017-12615 Tomcat PUT方法任意写文件漏洞
212 0
CVE-2017-12615 Tomcat PUT方法任意写文件漏洞
|
2月前
|
安全 网络协议 应用服务中间件
tomcat 状态页 及常见配置
tomcat 状态页 及常见配置