美文网首页
Netty编写一个静态资源服务器

Netty编写一个静态资源服务器

作者: 枫葉也 | 来源:发表于2021-01-15 00:20 被阅读0次

Netty编写一个静态资源服务器

上一篇文章我们了解了如何使用Netty编写一个极简的Http服务器 ,这一篇文章在上一篇文章的基础上,进一步编写一个静态资源服务器。

首先,HttpServer类与之前相同,不需要作修改,具体代码请见使用Netty编写一个极简的Http服务器 。我们修改HttpRequestHandler,来实现对静态资源请求的响应。

为了方便对Http请求的处理,我们先作如下规定:

  • 如果请求URI为“/”或“/index.html”,则直接返回index.html文件;
  • 如果请求URI以“/static”开头,则从/src/main/resources/static目录下根据URI中的文件名查找对应文件并返回给浏览器;
  • 如果请求URI不符合以上规则,则直接返回404未找到的Http响应。

首先我们在/src/main/resources目录下创建static文件夹,并添加几个测试文件,目录结构大概如下:

src
└── main
    ├── java
    │   └── ...
    └── resources
        ├── index.html
        └── static
            ├── test-image.jpg
            ├── test.txt
            └── 测试.txt

HttpRequestHandlerchannelRead0方法修改如下:

public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        System.out.println("request uri: " + msg.uri());
        if ("/".equals(msg.uri()) || "/index.html".equals(msg.uri())) {
            handleResource(ctx, msg, "index.html");
        } else if (msg.uri().startsWith("/static")) {
            handleResource(ctx, msg, msg.uri().substring(1));
        } else {
                        //处理请求链接不存在的情况
            handleNotFound(ctx, msg);
        }
    }

        //其他方法
}

handleNotFound方法用于请求链接不存在时,返回404未找到响应,主要代码如下:

private void handleNotFound(ChannelHandlerContext ctx, FullHttpRequest msg) {
    ByteBuf content = Unpooled.copiedBuffer("URL not found", CharsetUtil.UTF_8);
    HttpResponse response = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.NOT_FOUND, content);
    ChannelFuture future = ctx.writeAndFlush(response);
    future.addListener(ChannelFutureListener.CLOSE);
}

handleResource方法用于处理静态资源请求,也包括处理对主页index.html访问的处理:

private void handleResource(ChannelHandlerContext ctx, FullHttpRequest msg, String resource) throws IOException {
        String url = this.getClass().getResource("/").getPath() + resource;
        File file = new File(url);
        if (!file.exists()) {
            handleNotFound(ctx, msg);
            return;
        }
        if (file.isDirectory()) {
            handleDirectory(ctx, msg, file);
            return;
        }
        handleFile(ctx, msg, file);
    }

handleResource方法首先根据请求的文件名,拼装文件磁盘路径,获取对应的文件。如果文件不存在,则返回404的Http响应;如果对应路径是文件夹,则列出文件夹下的子文件;如果是文件,则返回对应的文件内容。

handleDirectory代码如下,此处只是简单地列出文件夹下的文件名称,还有很多细节需要完善。

private void handleDirectory(ChannelHandlerContext ctx, FullHttpRequest msg, File file) {
    StringBuilder sb = new StringBuilder();
    File[] files = file.listFiles();
    if (files != null) {
        for (File f : files) {
            if (f.isHidden() || !f.canRead()) {
                continue;
            }
            String name = f.getName();
            sb.append(name).append("<br/>");
        }
    }
    ByteBuf buffer = ctx.alloc().buffer(sb.length());
    buffer.writeCharSequence(sb.toString(), CharsetUtil.UTF_8);
    FullHttpResponse response = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK, buffer);
    response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
    ChannelFuture future = ctx.writeAndFlush(response);
    future.addListener(ChannelFutureListener.CLOSE);
}

handleFile方法如下:

private void handleFile(ChannelHandlerContext ctx, FullHttpRequest msg, File file) throws IOException {
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    HttpHeaders headers = getContentTypeHeader(file);
    HttpResponse response = new DefaultHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK, headers);
    ctx.write(response);
    ctx.write(new DefaultFileRegion(raf.getChannel(), 0, raf.length()));
    ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    future.addListener(ChannelFutureListener.CLOSE);
}

getContentTypeHeader方法:

private HttpHeaders getContentTypeHeader(File file) {
    MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
    HttpHeaders headers = new DefaultHttpHeaders();
    String contentType = mimeTypesMap.getContentType(file);
    if (contentType.equals("text/plain")) {
        //由于文本在浏览器中会显示乱码,此处指定为utf-8编码
        contentType = "text/plain;charset=utf-8";
    }
    headers.set(HttpHeaderNames.CONTENT_TYPE, contentType);
    return headers;
}

通过Java的MimetypesFileTypeMap工具类获取要传给浏览器的contentType,并将contentType设置到header中。测试过程中发现utf-8编码的txt文件在浏览器中会显示成乱码,因此如果获取的是文本文件,则将contentTypetext/plain改为text/plain;charset=utf-8

最终效果如下:

文件列表

https://i.loli.net/2021/01/14/hKUfXHL75Trnv6c.png

txt文件内容

https://i.loli.net/2021/01/14/l1nqQWaY5iLgokZ.png

获取图片文件

https://i.loli.net/2021/01/15/h597pMyrDNinRjP.png

相关文章

  • Netty编写一个静态资源服务器

    Netty编写一个静态资源服务器 上一篇文章我们了解了如何使用Netty编写一个极简的Http服务器[https:...

  • 静态、动态网页

    静态网页资源 什么是静态网页资源?静态网页资源是开发者编写的,放在服务器上看到的是什么显示的就是什么,一旦编写完成...

  • java完成ftp传输(将文件上传至静态资源服务器)

    Nginx实现静态资源服务器 apache实现静态资源服务器 参考文章记录 JavaWeb静态资源分离思路 jav...

  • nginx能做什么好玩的事情?

    一、HTTP服务器 Nginx本身也是一个静态资源的服务器,当只有静态资源的时候,就可以使用Nginx来做服务器,...

  • Nginx静态服务

    搭建一个Nginx静态资源Web服务器

  • day4--node的静态资源服务器

    笔记 作业:完善上的代码,实现一个静态资源服务器。 作用 完善课上的代码实现一个静态资源服务器。 创建三个文件:程...

  • 场景实践篇

    静态资源web服务 静态资源 定义 非服务器动态生成的文件 静态资源服务场景-CDN 文件读取配置 sendfil...

  • 当前文集 node.js 写一个静态资源服务器记录,是为了给自己学习用 node.js 写静态资源服务器做一个记录...

  • nginx 从入门到入门

    Nginx是俄罗斯人用c++编写的十分轻量级的HTTP服务器,同时也能作为邮件服务器、反向代理服务器、静态资源服务...

  • 07.Nginx静态资源配置

    1.静态资源类型 Nginx 作为静态资源 Web 服务器部署配置, 传输⾮常的⾼效, 常常⽤于静态资源处理, 请...

网友评论

      本文标题:Netty编写一个静态资源服务器

      本文链接:https://www.haomeiwen.com/subject/rfciaktx.html