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


目录
相关文章
|
2月前
|
消息中间件 编解码 网络协议
Netty从入门到精通:高性能网络编程的进阶之路
【11月更文挑战第17天】Netty是一个基于Java NIO(Non-blocking I/O)的高性能、异步事件驱动的网络应用框架。使用Netty,开发者可以快速、高效地开发可扩展的网络服务器和客户端程序。本文将带您从Netty的背景、业务场景、功能点、解决问题的关键、底层原理实现,到编写一个详细的Java示例,全面了解Netty,帮助您从入门到精通。
245 0
|
2月前
|
存储 弹性计算 NoSQL
"从入门到实践,全方位解析云服务器ECS的秘密——手把手教你轻松驾驭阿里云的强大计算力!"
【10月更文挑战第23天】云服务器ECS(Elastic Compute Service)是阿里云提供的基础云计算服务,允许用户在云端租用和管理虚拟服务器。ECS具有弹性伸缩、按需付费、简单易用等特点,适用于网站托管、数据库部署、大数据分析等多种场景。本文介绍ECS的基本概念、使用场景及快速上手指南。
107 3
|
3月前
使用Netty实现文件传输的HTTP服务器和客户端
本文通过详细的代码示例,展示了如何使用Netty框架实现一个文件传输的HTTP服务器和客户端,包括服务端的文件处理和客户端的文件请求与接收。
97 1
使用Netty实现文件传输的HTTP服务器和客户端
|
3月前
|
安全 Java 应用服务中间件
【服务器知识】Tomcat简单入门
【服务器知识】Tomcat简单入门
|
5月前
|
API 开发者
Netty运行原理问题之Netty实现低开发门槛的问题如何解决
Netty运行原理问题之Netty实现低开发门槛的问题如何解决
|
5月前
|
前端开发 网络协议 物联网
Django Web:搭建Websocket服务器(入门篇)
Django Web:搭建Websocket服务器(入门篇)
158 1
|
6月前
|
前端开发 JavaScript
【node写接口】 通过node 快速搭建一个服务器、get请求、post请求 小白入门
【node写接口】 通过node 快速搭建一个服务器、get请求、post请求 小白入门
194 4
|
6月前
|
网络协议 网络架构
【网络编程入门】TCP与UDP通信实战:从零构建服务器与客户端对话(附简易源码,新手友好!)
在了解他们之前我们首先要知道网络模型,它分为两种,一种是OSI,一种是TCP/IP,当然他们的模型图是不同的,如下
244 1
|
6月前
|
弹性计算 网络安全 数据安全/隐私保护
阿里云服务器新手入门:注册账号、实名认证申请免费云服务器全流程
注册阿里云账号,选择注册方式如密码、扫码或手机号,并完成验证码验证。接着进行实名认证,提供必要个人信息或企业证件。然后,在控制台选择云服务器ECS,点击“免费试用”申请,配置实例并设置登录密码。创建后,通过远程连接工具如SSH登录,开始使用服务器进行软件安装、应用部署等操作。阿里云提供详细文档支持。别忘了点击链接以直接试用。
303 0
|
3天前
|
弹性计算 数据挖掘 应用服务中间件
阿里云轻量应用服务器68元与云服务器99元和199元区别及选择参考
目前阿里云有三款特惠云服务器,第一款轻量云服务器2核2G68元一年,第二款经济型云服务器2核2G3M带宽99元1年,第三款通用算力型2核4G5M带宽199元一年。有的新手用户并不是很清楚他们之间的区别,因此不知道如何选择。本文来介绍一下它们之间的区别以及选择参考。
149 84