使用Netty实现静态网页服务器

使用Netty实现Http服务器及客户端 中,我们学习到了如何使用Netty来实现一个简单的Http服务器,这里我们只需要将其进行简单的修改,就可以当做一个静态的网页服务器的,其项目结构如下:
在这里插入图片描述

首先是其服务端,学习了Netty之后,发现其实都是非常标准的一套写法,如下:

public final class StaticServer {

    public static void main(String[] args) throws Exception {
        StaticServer server = new StaticServer();
        server.start(8080);
    }

    private void start(int port) throws Exception {
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup work = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 512)
                    .childHandler(new StaticServerInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            boss.shutdownGracefully();
            work.shutdownGracefully();
        }
    }
}

然后就是添加的相关的ChildHandler,添加了些支持Http请求等,其内容如下:

public class StaticServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        //增加对http的支持
        pipeline.addLast(new HttpServerCodec());
        pipeline.addLast(new HttpObjectAggregator(65536));

        pipeline.addLast(new ChunkedWriteHandler());

        pipeline.addLast(new StaticServerHandler());
    }
}

最后就关键的就是我们对请求静态网页资源的请求进行处理,包括获取资源的路径,文件不存在的处理,文件格式的处理,以及限制其访问方式等等

public class StaticServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        // 状态为1xx的话,继续请求
        if (HttpUtil.is100ContinueExpected(request)) {
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
            ctx.writeAndFlush(response);
        }

        //处理错误或者无法解析的http请求
        if (!request.decoderResult().isSuccess()) {
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST,
                    Unpooled.copiedBuffer("请求失败", CharsetUtil.UTF_8));

            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }

        //这里设置了只允许GET请求
        if (request.method() != HttpMethod.GET) {
            DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN);

            ByteBuf byteBuf = Unpooled.copiedBuffer("只允许GET请求", CharsetUtil.UTF_8);
            response.content().writeBytes(byteBuf);
            byteBuf.release();

            HttpUtil.setContentLength(response, response.content().readableBytes());
            ctx.channel().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }

        String uri = request.uri();
        String path = this.getClass().getClassLoader().getResource("static").getPath() + uri;
        File file = new File(path);

        //设置不支持favicon.ico文件
        if ("/favicon.ico".equals(uri)) {
            return;
        }

        //文件没有发现设置404
        if (!file.exists()) {
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND,
                    Unpooled.copiedBuffer("访问路径错误", CharsetUtil.UTF_8));

            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=UTF-8");
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }

        HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);
        //设置文件格式内容
        if (path.endsWith(".html")) {
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html;charset=UTF-8");
        } else if (path.endsWith(".js")) {
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/x-javascript");
        } else if (path.endsWith(".css")) {
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/css;charset=UTF-8");
        }

        if (HttpUtil.isKeepAlive(request)) {
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, file.length());
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }
        ctx.write(response);

        RandomAccessFile ra = new RandomAccessFile(file, "r");
        if (ctx.pipeline().get(SslHandler.class) == null) {
            ctx.write(new DefaultFileRegion(ra.getChannel(), 0, ra.length()));
        } else {
            ctx.write(new ChunkedNioFile(ra.getChannel()));
        }

        ChannelFuture channelFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        if (!HttpUtil.isKeepAlive(request)) {
            channelFuture.addListener(ChannelFutureListener.CLOSE);
        }
        ra.close();
    }
}

上述我们就根据之前的Http进行简单修改实现的静态网页服务器,其实都是差不多,只不过在获取到访问路径后,我们在项目中获取其对应路径在的相关文件资源,然后将其返回给客户端而已。


按照上述设置的路径,这里我们在resources文件目录下的static文件夹下,放置一个简单的html文件及其相关css样式、图片等,该静态网页就是模仿美团首页写的静态网页
在这里插入图片描述


启动该项目,我们直接进行访问其index.html文件,其结果截图如下:
在这里插入图片描述
在这里插入图片描述

发布了286 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/newbie0107/article/details/104592707