简介

  • HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写
  • HTTP是一个基于TCP/IP通信协议来传递数据

工作原理

  • HTTP协议工作于C/S架构上,浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求
  • Web服务器根据接收到的请求后,向客户端发送响应信息
  • HTTP默认端口号为80,但是你也可以改为8080或者其他端口
  • HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
  • HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。
  • HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

编写Http Servlet规范类

Servlet抽象类

/**
 * Servlet
 *
 * @author LionLi
 */
public abstract class Servlet {

    public abstract void doGet(Request request,Response response);

    public abstract void doPost(Request request,Response response);

}

Request相关功能实现 

/**
 * Request
 *
 * @author LionLi
 */
public class Request {

    private ChannelHandlerContext ctx;

    private HttpRequest r;

    public Request(ChannelHandlerContext ctx, HttpRequest r) {
        this.ctx = ctx;
        this.r = r;
    }

    public String getUri() {
        return r.uri();
    }

    public String getMethod() {
        return r.method().name();
    }

    public Map<String, List<String>> getParameters() {
        QueryStringDecoder decoder = new QueryStringDecoder(r.uri());
        return decoder.parameters();
    }

    public String getParameter(String name) {
        Map<String, List<String>> params = getParameters();
        List<String> param = params.get(name);
        if (null == param) {
            return null;
        } else {
            return param.get(0);
        }
    }

}

Response相关功能实现

/**
 * Response
 *
 * @author LionLi
 */
public class Response {

    private ChannelHandlerContext ctx;

    private HttpRequest r;

    public Response(ChannelHandlerContext ctx, HttpRequest r) {
        this.ctx = ctx;
        this.r = r;
    }

    public void write(String out) throws Exception {
        try {
            if (out == null || out.length() == 0) {
                return;
            }
            // 设置 http协议及请求头信息
            FullHttpResponse response = new DefaultFullHttpResponse(
                    // 设置http版本为1.1
                    HttpVersion.HTTP_1_1,
                    // 设置响应状态码
                    HttpResponseStatus.OK,
                    // 将输出值写出 编码为UTF-8
                    Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
            // 设置连接类型 为 JSON
            response.headers().set(CONTENT_TYPE, "text/json");
            // 设置请求头长度
            response.headers().set(CONTENT_LANGUAGE, response.content().readableBytes());
            // 设置超时时间为5000ms
            response.headers().set(EXPIRES, 5000);
            // 当前是否支持长连接
//            if (HttpUtil.isKeepAlive(r)) {
//                // 设置连接内容为长连接
//                response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
//            }
            ctx.write(response);
        } finally {
            ctx.flush();
            ctx.close();
        }
    }

}

自定义Servlet处理

/**
 * servlet处理
 *
 * @author LionLi
 */
public class MyServlet extends Servlet {

    public void doGet(Request request, Response response) {
        try {
            // 获取 name 参数 并返回
            response.write(request.getParameter("name"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void doPost(Request request, Response response) {
        doGet(request,response);
    }

}

编写Server相关类

http服务器主类

/**
 * http服务器
 *
 * @author LionLi
 */
public class HttpServer {

    public void start(int port) throws Exception {

        // Boss线程
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // Worker线程
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap server = new ServerBootstrap();
            server.group(bossGroup, workerGroup)
                    // 主线程处理类
                    .channel(NioServerSocketChannel.class)
                    // 子线程处理类
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        // 客户端初始化处理
                        protected void initChannel(SocketChannel client) {
                            // HttpResponseEncoder 编码器
                            client.pipeline().addLast(new HttpResponseEncoder());
                            // HttpRequestDecoder 解码器
                            client.pipeline().addLast(new HttpRequestDecoder());
                            // 业务逻辑处理
                            client.pipeline().addLast(new HttpHandler());
                        }

                    })
                    // 针对主线程的配置 分配线程最大数量 128
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 针对子线程的配置 保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // 启动服务器 sync 同步阻塞
            ChannelFuture f = server.bind(port).sync();
            System.out.println("HttpServer Startd Port: " + port);
            f.channel().closeFuture().sync();
        } finally {
            // 关闭线程池
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        try {
            new HttpServer().start(8088);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

业务处理Handler类

/**
 * 业务处理
 *
 * @author LionLi
 */
public class HttpHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof HttpRequest){
            HttpRequest r = (HttpRequest) msg;

            Request request = new Request(ctx,r);
            Response response = new Response(ctx,r);

            MyServlet.class.newInstance().doGet(request,response);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

    }
}

测试

启动HttpServer

java netty 发送tcp消息 netty发送http请求_netty

启动成功无异常

访问netty服务器 http://localhost:8088/?name=LionLi

java netty 发送tcp消息 netty发送http请求_netty_02

成功返回结果

项目已上传到gitee