快速入门实例-HTTP 服务

实例要求:使用IDEA创建Netty项目

Netty 服务器在 6668 端口监听,浏览器发出请求 “http://localhost:6668/

服务器可以回复消息给客户端 “Hello! 我是服务器 5 “ , 并对特定请求资源进行过滤.

目的:Netty可以做Http服务开发,并且理解Handler实例和客户端及其请求的关系.

image-20201109102352975

这次,我们将把这个类抽取出来,单独创建。而不是继续使用匿名类的方式。

image-20201109102907226

image-20201109102935224

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TestServer {
public static void main(String[] args) throws InterruptedException {

NioEventLoopGroup boosGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup(8);

try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(boosGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new TestServerInitializer());

ChannelFuture channelFuture = serverBootstrap.bind(6668).sync();

channelFuture.channel().closeFuture().sync();
} finally {
boosGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

继承ChannelInitializer<SocketChannel>,重写initChannel方法完成初始化。

image-20201109103716277

new HttpServerCodec()Netty提供的Http的编-解码器。可以在前面自定义名字,不加使用默认的。

接着编写自己创建的handler。

1.SimpleChannel 是 ChannelInboundHandlerAdapter的子类

2.HttpObject 客户端和服务端相互通信的数据被封装成HttpObject

channelRead0()读取客户端数据

image-20201109104438247

image-20201109104538598

image-20201109104350047

接着启动服务端。网页访问http://localhost:6668/

image-20201109104649437

这是因为端口(6665-6669等)是一些浏览器的默认非安全端口,浏览器给拦截了。

我们将端口改成1111,访问http://localhost:1111/

image-20201109104946885

image-20201109105018978

Http服务过滤资源

当我们使用谷歌浏览器访问时,会发现浏览器发送了两次请求。

image-20201109105214189

image-20201109105225460

/favicon.ico是一些浏览器的默认行为,是请求网站图标的。

我们如何将类似请求过滤掉呢??

我们可以通过把HttpObject msg强转为HttpRequest对象。然后通过httpRequest.uri()构建一个URI对象,接着通过uri.getPath()判断uri是否为/favicon.ico。如果是的话直接返回不会接着处理。

image-20201109110136734

同时每个浏览器的pipeline和hanlder都是独立的。每个人都是人手一份的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* 1.SimpleChannel 是 ChannelInboundHandlerAdapter的子类
* 2.HttpObject 客户端和服务端相互通信的数据被封装成HttpObject
*/
public class TestHttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {


//读取客户端数据
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

//判断msg是不是HttpRequest请求
if (msg instanceof HttpRequest) {
System.out.println("msg 类型=" + msg.getClass());
System.out.println("客户端地址" + ctx.channel().remoteAddress());

System.out.println("pipeline hashcode=" + ctx.pipeline().hashCode() + "TestHttpServerHandler hash=" + this.hashCode());


//获取到
HttpRequest httpRequest = (HttpRequest) msg;
//获取uri 过滤指定路径
URI uri = new URI(httpRequest.uri());
if ("/favicon.ico".equals(uri.getPath())) {
System.out.println("请求了favicon.ico,不做响应~");
return;
}

//回复信息给浏览器【Http协议】
ByteBuf content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_8);

//构造一个http响应,即Http response
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);

response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=utf8");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());

//将构建好的response返回
ctx.writeAndFlush(response);

}
}
}

重启服务端。浏览器访问。

image-20201109110433118

image-20201109110454763

再启动一个浏览器访问

image-20201109110552633

hash值是不一样的。也就是不是同一个。