Using Netty to Realize Static Web Server

In use Netty achieve Http server and client , we learned how to use Netty to implement a simple Http server, where we just want it simple modifications, can be used as a static web server, the project is structured as follows :
Insert picture description here

The first is its server. After learning Netty, I found that it is actually a very standard set of writing, as follows:

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();
        }
    }
}

Then there is the related ChildHandler added, some support for Http requests, etc. are added, the contents are as follows:

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());
    }
}

Finally, the key is that we process requests for static web page resources, including access to resources, processing of non-existent files, processing of file formats, and restricting their access methods, etc.

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();
    }
}

The static web server that we implemented based on the previous Http simple modification is actually similar, but after obtaining the access path, we obtain the relevant file resources in the corresponding path in the project, and then return it to the client That's it.


According to the path set above, here we put a simple html file and its related css styles, pictures, etc. in the static folder under the resources file directory. This static webpage is a static webpage imitating the homepage of Meituan.
Insert picture description here


Starting the project, we directly access its index.html file, and the result screenshot is as follows:
Insert picture description here
Insert picture description here

286 original articles published · Liked12 · Visitors 10,000+

Guess you like

Origin blog.csdn.net/newbie0107/article/details/104592707