Netty入门到超神系列-Netty开发Http服务器

简介: 这章我们使用Netty来写一个Http服务器类似于Tomcat ,当然Netty和Tomcat是有很多的异同的,比如通信协议,Tomcat是一个基于Http协议的Web容器,而Netty能够通过codec自己来编码/解码字节流 ,因此Netty可以通过编程自定义各种协议,我们今天的目的还是对Netty练练手。

前言

这章我们使用Netty来写一个Http服务器类似于Tomcat ,当然Netty和Tomcat是有很多的异同的,比如通信协议,Tomcat是一个基于Http协议的Web容器,而Netty能够通过codec自己来编码/解码字节流 ,因此Netty可以通过编程自定义各种协议,我们今天的目的还是对Netty练练手。

基于Netty的Http服务器

我这里要实现的案例就是客户端(浏览器或者Postmain)请求服务器,发送GET或者Post请求,服务器拿到请求中的参数,然后返回一个消息给客户端.

对于Netty服务端和之前的入门程序差不多,大致流程都是一样的,只不过这次需要给 SocketChannel中的pipeline添加编码和解码器。

  • HttpRequestDecoder 请求解码器
  • HttpResponseEncoder 响应转码器

对于Handler而言,我们需要继承 SimpleChannelInboundHandler<FullHttpRequest>, 泛型FullHttpRequest 就是对请求对象的封装,通过它我们可以获取到请求相关的内容。

服务器代码

publicclassNettyHttpServer {
publicstaticvoidmain(String[] args) throwsInterruptedException {
//事件循环组NioEventLoopGroupbossGroup=newNioEventLoopGroup();
NioEventLoopGroupworkGroup=newNioEventLoopGroup();
//启动对象ServerBootstrapbootstrap=newServerBootstrap() ;
try {
//配置nettybootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(newChannelInitializer<SocketChannel>(){
@OverrideprotectedvoidinitChannel(SocketChannelch) throwsException {
// 请求解码器ch.pipeline().addLast("http-decoder", newHttpRequestDecoder());
// 将HTTP消息的多个部分合成一条完整的HTTP消息ch.pipeline().addLast("http-aggregator", newHttpObjectAggregator(65535));
// 响应转码器ch.pipeline().addLast("http-encoder", newHttpResponseEncoder());
// 解决大码流的问题,ChunkedWriteHandler:向客户端发送HTML5文件ch.pipeline().addLast("http-chunked", newChunkedWriteHandler());
//添加处理器到pipelinech.pipeline().addLast("http-server",newHttpServerHandler());
                        }
                    });
//启动服务,监听端口,同步返回ChannelFuturechannelFuture=bootstrap.bind(newInetSocketAddress("127.0.0.1", 6666)).sync();
// 当通道关闭时继续向后执行,这是一个阻塞方法channelFuture.channel().closeFuture().sync();
        } catch (InterruptedExceptione) {
e.printStackTrace();
        } finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
        }
    }
}

相比之前的入门案例来说,就是给 pipeline 多添加了一堆编码器,目的就是对Http请求或响应进行编码。

处理器代码

handler中需要根据请求Method判断是GET或者POST,对于POST还要判断是普通表单提交还是JSON提交。然后根据不同的请求方式取到请求参数。最后把“Hello Netty”返回给客户端。

packagecn.itsource.nio.httpserver;
importcom.alibaba.fastjson.JSON;
importcom.alibaba.fastjson.JSONObject;
importcom.sun.deploy.util.StringUtils;
importio.netty.buffer.ByteBuf;
importio.netty.buffer.Unpooled;
importio.netty.channel.ChannelHandlerContext;
importio.netty.channel.SimpleChannelInboundHandler;
importio.netty.handler.codec.http.*;
importio.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
importio.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
importio.netty.handler.codec.http.multipart.InterfaceHttpData;
importio.netty.handler.codec.http.multipart.MemoryAttribute;
importio.netty.util.CharsetUtil;
importjava.io.UnsupportedEncodingException;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
publicclassHttpServerHandlerextendsSimpleChannelInboundHandler<FullHttpRequest> {
//该方法的作用是用来读取客户端的数据, FullHttpRequest 请求对象@OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx, FullHttpRequestrequest) throwsException {
System.out.println("客户端:"+ctx.channel().remoteAddress()+" 发来请求");
//读取数据Map<String, Object>data=readData(request);
System.out.println("data:"+data);
//根据请求参数,处理不同的业务,做出不同的响应//就返回一个Hello好了Stringcontent="Hello Netty";
//响应数据writeDate(ctx,request,content);
    }
//写数据给客户端privatevoidwriteDate(ChannelHandlerContextctx,FullHttpRequestrequest,Stringcontent) {
//把数据拷贝到bufferByteBufbuffer=Unpooled.copiedBuffer(content, CharsetUtil.UTF_8);
//创建Http响应对象,设置http版本和状态吗,以及数据DefaultFullHttpResponsehttpResponse=newDefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,buffer);
//响应头信息httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plan");
httpResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
//响应结果ctx.writeAndFlush(httpResponse);
    }
//读取数据,get,或者postpublicMap<String,Object>readData(FullHttpRequestrequest){
Map<String, Object>param=null;
if(request.method() ==HttpMethod.GET){
param=getGetParams(request);
        }elseif(request.method() ==HttpMethod.POST){
param=getPostParams(request);
        }
System.out.println(param);
returnparam;
    }
//获取GET方式传递的参数privateMap<String, Object>getGetParams(FullHttpRequestfullHttpRequest) {
Map<String, Object>params=newHashMap<String, Object>();
if (fullHttpRequest.method() ==HttpMethod.GET) {
// 处理get请求QueryStringDecoderdecoder=newQueryStringDecoder(fullHttpRequest.uri());
Map<String, List<String>>paramList=decoder.parameters();
for (Map.Entry<String, List<String>>entry : paramList.entrySet()) {
params.put(entry.getKey(), entry.getValue().get(0));
            }
returnparams;
        }
returnnull;
    }
//获取POST方式传递的参数privateMap<String, Object>getPostParams(FullHttpRequestfullHttpRequest) {
if (fullHttpRequest.method() ==HttpMethod.POST) {
// 处理POST请求StringstrContentType=fullHttpRequest.headers().get("Content-Type").trim();
if (strContentType.contains("x-www-form-urlencoded")) {
returngetFormParams(fullHttpRequest);
            } elseif (strContentType.contains("application/json")) {
returngetJSONParams(fullHttpRequest);
            }
        }
returnnull;
    }
//解析JSON数据privateMap<String, Object>getJSONParams(FullHttpRequestfullHttpRequest)  {
ByteBufcontent=fullHttpRequest.content();
byte[] reqContent=newbyte[content.readableBytes()];
content.readBytes(reqContent);
try {
returnJSON.parseObject(newString(reqContent, "UTF-8"),Map.class);
        } catch (UnsupportedEncodingExceptione) {
e.printStackTrace();
        }
returnnull;
    }
//解析from表单数据(Content-Type = x-www-form-urlencoded)privateMap<String, Object>getFormParams(FullHttpRequestfullHttpRequest) {
Map<String, Object>params=newHashMap<String, Object>();
HttpPostRequestDecoderdecoder=newHttpPostRequestDecoder(newDefaultHttpDataFactory(false), fullHttpRequest);
List<InterfaceHttpData>postData=decoder.getBodyHttpDatas();
for (InterfaceHttpDatadata : postData) {
if (data.getHttpDataType() ==InterfaceHttpData.HttpDataType.Attribute) {
MemoryAttributeattribute= (MemoryAttribute) data;
params.put(attribute.getName(), attribute.getValue());
            }
        }
returnparams;
    }
}


目录
相关文章
|
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
|
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%性能
122 14
|
1月前
|
存储 弹性计算 运维
阿里云日常运维-购买服务器
这篇文章是关于如何在阿里云购买和配置云服务器ECS的教程。
60 6
阿里云日常运维-购买服务器
下一篇
无影云桌面