netty实现http服务器

简介: 1. HttpServerHttpServer作为http服务器的server端:public final class HttpServer { private static final String IP = "127.

1. HttpServer

HttpServer作为http服务器的server端:

public final class HttpServer {

    private static final String IP = "127.0.0.1";
    private static final int PORT = 9000;
    private static final int BIZ_THREAD_SIZE = 100;

    private static final Logger logger = LoggerFactory.getLogger(HttpServer.class);

    public static void main(String[] args) throws Exception {
        System.out.println("启动Server...");
        HttpServer.start();
    }

    public static void start() throws Exception {
        initServerConfig();

        // new NioEventLoopGroup()默认线程数为CPU核心数的两倍(Runtime.getRuntime().availableProcessors() * 2),所以这里不用额外指定。
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 这里worker不能使用默认,如果并发大的话需要增加线程数量
        EventLoopGroup workerGroup = new NioEventLoopGroup(BIZ_THREAD_SIZE);

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // ChannelOption.SO_BACKLOG对应的是tcp/ip协议listen函数中的backlog参数。函数listen(int socketfd, int backlog)用来初始化服务端可连接队列。
                    // 服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接,多个客户端来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理,backlog参数指定了队列的大小。
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 子channel配置,保持长连接
                    .childHandler(new HttpServerInitializer());

            // sync追踪代码可以得到:this.await(),实现阻塞
            ChannelFuture channelFuture = bootstrap.bind(IP, PORT).sync();

            // 启动失败则关闭线程组
            if (!channelFuture.isSuccess()) {
                shutdown(bossGroup, workerGroup);
                throw new RuntimeException(channelFuture.cause());
            }

            channelFuture.channel().closeFuture().sync();
            logger.info("bootstrap channel closed...");
        } finally {
            shutdown(bossGroup, workerGroup);
        }
    }

    // 添加路径映射和过滤器映射
    private static void initServerConfig() {
        ServerContext.setFilter(ServerContext.MAPPING_ALL, BaseFilter.class);
        ServerContext.setFilter("/template", TemplateFilter.class);
        ServerContext.setAction(ServerContext.MAPPING_ALL, DefaultIndexAction.class);
        ServerContext.setAction("/template", TemplateAction.class);
        ServerContext.setAction("/files", FileAction.class);
        ServerContext.setROOT("root");
        ServerContext.setPORT(8090);
    }

    private static void shutdown(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}

HttpServerInitializer设置http编解码器,以及请求aggregator等:

public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    public void initChannel(SocketChannel socketChannel) {
        ChannelPipeline pipeline = socketChannel.pipeline();
        pipeline
                //或者使用HttpRequestDecoder & HttpResponseEncoder
                .addLast(new HttpServerCodec())
                //把HttpObjectAggregator放入管道里。HttpObjectAggregator会把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse
                .addLast(new HttpObjectAggregator(1024 * 1024))
                //压缩Http消息
//                            .addLast(new HttpChunkContentCompressor())
                //大文件支持,文件上传时使用
//                            .addLast(new ChunkedWriteHandler())
                .addLast(new HttpServerExpectContinueHandler())
                .addLast(new HttpServerDispatcherHandler());
    }
}

入栈处理器,用于转发http请求,类似于DispatcherServlet:

public class HttpServerDispatcherHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        if (!(msg instanceof FullHttpRequest)) {
            return;
        }

        FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
        final Request customerRequest = Request.build(ctx, fullHttpRequest);
        final Response customerResponse = Response.build(ctx, customerRequest);
        if (customerRequest.getRequestUrl().equals(HttpHelper.FAVICON_ICO)) {
            return;
        }

        // 过滤器放行之后,执行action,实际处理业务逻辑
        boolean passFilter = doFilter(customerRequest, customerResponse);
        if (passFilter) {
            doAction(customerRequest, customerResponse);
        }

        //如果发送请求未被触发,则触发之,否则跳过。
        if(false == customerResponse.isSent()) {
            customerResponse.response();
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    /**
     * 过滤器
     * @param request
     * @param response
     * @return
     */
    private boolean doFilter(Request request, Response response) {
        //全局过滤器
        Filter filter = ServerContext.getFilter(ServerContext.MAPPING_ALL);
        if(null != filter) {
            if(false == filter.doFilter(request, response)) {
                return false;
            }
        }

        //自定义过滤器
        filter = ServerContext.getFilter(request.getRequestUrl());
        if(null != filter) {
            if(false == filter.doFilter(request, response)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 请求处理器
     * 相当于servlet
     * @param request
     * @param response
     */
    private void doAction(Request request, Response response) {
        Action action = ServerContext.getAction(request.getRequestUrl());
        if (null == action) {
            //查找匹配所有路径的Action
            action = ServerContext.getAction(ServerContext.MAPPING_ALL);
            if(null == action) {
                // 非Action方法,调用静态文件读取
                action = Singleton.get(FileAction.class);
            }
        }

        action.doAction(request, response);
    }
}

过滤器

public interface Filter {
    
    /**
     * 执行过滤
     * @param request 请求对象
     * @param response 响应对象
     * @return 如果返回true,则继续执行下一步内容,否则中断
     */
    boolean doFilter(Request request, Response response);
}

过滤器示例:

public class TemplateFilter implements Filter {

    @Override
    public boolean doFilter(Request request, Response response) {
        System.out.println("welcome in template filter...");
        return true;
    }
}

action

action用于实际处理业务,顶层接口:

public interface Action {

    void doAction(Request request, Response response);
}

抽象Adapter:

public abstract class AbstractAction implements Action {

    @Override
    public void doAction(Request request, Response response) {
        String method = request.getMethod();
        if (HttpHelper.METHOD_GET.equals(method)) {
            doGet(request, response);
        } else if (HttpHelper.METHOD_POST.equals(method)) {
            doPost(request, response);
        } else if (HttpHelper.METHOD_PUT.equals(method)) {
            doPut(request, response);
        } else if (HttpHelper.METHOD_DELETE.equals(method)) {
            doDelete(request, response);
        } else if (HttpHelper.METHOD_HEAD.equals(method)) {
            doHead(request, response);
        } else if (HttpHelper.METHOD_OPTIONS.equals(method)) {
            doOptions(request, response);
        } else if (HttpHelper.METHOD_TRACE.equals(method)) {
            doTrace(request, response);
        }
    }

    protected void doGet(Request request, Response response) {}

    protected void doPost(Request request, Response response) {}

    protected void doPut(Request request, Response response) {}

    protected void doDelete(Request request, Response response) {}

    protected void doOptions(Request request, Response response) {}

    protected void doHead(Request request, Response response) {}

    protected void doTrace(Request request, Response response) {}
}

action示例:

public class TemplateAction extends AbstractAction {

    @Override
    protected void doGet(Request request, Response response) {
        response.setContentType(HttpHelper.CONTENT_TYPE_JSON);
        response.setContent("welcome in template action, do get...");
    }

    @Override
    protected void doPost(Request request, Response response) {
        response.setContent("welcome in template action, do post...");
    }
}

。。。

目录
相关文章
|
24天前
|
开发者
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
24 1
|
2月前
|
缓存 数据安全/隐私保护 UED
代理服务器在HTTP请求中的应用:Ruby实例
代理服务器在HTTP请求中的应用:Ruby实例
|
3月前
|
存储 运维 Java
函数计算产品使用问题之如何使用Python的requests库向HTTP服务器发送GET请求
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
100 8
|
2月前
|
移动开发 网络协议 编译器
实战案例3:C语言实现的HTTP服务器
实战案例3:C语言实现的HTTP服务器
51 0
|
3月前
|
缓存 程序员 开发者
HTTP状态码大全:如何读懂服务器的语言?
大家好,我是小米,今天我们来聊聊HTTP协议中的GET和POST请求。它们在数据传输方式、安全性和应用场景上有不同特点。本文将详细解析它们的区别和特点,帮助你更好地理解和运用这两种请求方式。让我们一起学习吧!
43 1
|
25天前
|
Cloud Native Java 编译器
将基于x86架构平台的应用迁移到阿里云倚天实例云服务器参考
随着云计算技术的不断发展,云服务商们不断推出高性能、高可用的云服务器实例,以满足企业日益增长的计算需求。阿里云推出的倚天实例,凭借其基于ARM架构的倚天710处理器,提供了卓越的计算能力和能效比,特别适用于云原生、高性能计算等场景。然而,有的用户需要将传统基于x86平台的应用迁移到倚天实例上,本文将介绍如何将基于x86架构平台的应用迁移到阿里云倚天实例的服务器上,帮助开发者和企业用户顺利完成迁移工作,享受更高效、更经济的云服务。
将基于x86架构平台的应用迁移到阿里云倚天实例云服务器参考
|
23天前
|
编解码 前端开发 安全
通过阿里云的活动购买云服务器时如何选择实例、带宽、云盘
在我们选购阿里云服务器的过程中,不管是新用户还是老用户通常都是通过阿里云的活动去买了,一是价格更加实惠,二是活动中的云服务器配置比较丰富,足可以满足大部分用户的需求,但是面对琳琅满目的云服务器实例、带宽和云盘选项,如何选择更适合自己,成为许多用户比较关注的问题。本文将介绍如何在阿里云的活动中选择合适的云服务器实例、带宽和云盘,以供参考和选择。
通过阿里云的活动购买云服务器时如何选择实例、带宽、云盘
|
21天前
|
弹性计算 运维 安全
阿里云轻量应用服务器和经济型e实例区别及选择参考
目前在阿里云的活动中,轻量应用服务器2核2G3M带宽价格为82元1年,2核2G3M带宽的经济型e实例云服务器价格99元1年,对于云服务器配置和性能要求不是很高的阿里云用户来说,这两款服务器配置和价格都差不多,阿里云轻量应用服务器和ECS云服务器让用户二选一,很多用户不清楚如何选择,本文来说说轻量应用服务器和经济型e实例的区别及选择参考。
阿里云轻量应用服务器和经济型e实例区别及选择参考
|
22天前
|
机器学习/深度学习 存储 人工智能
阿里云GPU云服务器实例规格gn6v、gn7i、gn6i实例性能及区别和选择参考
阿里云的GPU云服务器产品线在深度学习、科学计算、图形渲染等多个领域展现出强大的计算能力和广泛的应用价值。本文将详细介绍阿里云GPU云服务器中的gn6v、gn7i、gn6i三个实例规格族的性能特点、区别及选择参考,帮助用户根据自身需求选择合适的GPU云服务器实例。
阿里云GPU云服务器实例规格gn6v、gn7i、gn6i实例性能及区别和选择参考
|
15天前
|
弹性计算 人工智能 安全
阿里云推出第九代ECS实例,最高提升30%性能
阿里云推出第九代ECS实例,最高提升30%性能
123 14
下一篇
无影云桌面