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


目录
相关文章
|
9月前
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
513 18
|
9月前
|
应用服务中间件 网络安全 数据安全/隐私保护
网关服务器配置指南:实现自动DHCP地址分配、HTTP服务和SSH无密码登录。
哇哈哈,道具都准备好了,咱们的魔术秀就要开始了。现在,你的网关服务器已经魔法满满,自动分配IP,提供网页服务,SSH登录如入无人之境。而整个世界,只会知道效果,不会知道是你在幕后操控一切。这就是真正的数字世界魔法师,随手拈来,手到擒来。
477 14
|
8月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
8月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
585 0
|
10月前
|
安全 网络协议 Linux
Linux网络应用层协议展示:HTTP与HTTPS
此外,必须注意,从HTTP迁移到HTTPS是一项重要且必要的任务,因为这不仅关乎用户信息的安全,也有利于你的网站评级和粉丝的信心。在网络世界中,信息的安全就是一切,选择HTTPS,让您的网站更加安全,使您的用户满意,也使您感到满意。
303 18
|
监控 安全 搜索推荐
设置 HTTPS 协议以确保数据传输的安全性
设置 HTTPS 协议以确保数据传输的安全性
|
10月前
|
网络安全 开发者
如何解决HTTPS协议在WordPress升级后对网站不兼容的问题
以上就是解决WordPress升级后HTTPS协议对网站的不兼容问题的方法。希望能把这个棘手的问题看成是学校的管理问题一样来应对,将复杂的技术问题变得更加有趣和形象,并寻觅出解决问题的方式。希望你的网站能在新的学期得到更好的发展!
281 19
|
10月前
|
JSON 安全 网络协议
HTTP/HTTPS协议(请求响应模型、状态码)
本文简要介绍了HTTP与HTTPS协议的基础知识。HTTP是一种无状态的超文本传输协议,基于TCP/IP,常用80端口,通过请求-响应模型实现客户端与服务器间的通信;HTTPS为HTTP的安全版本,基于SSL/TLS加密技术,使用443端口,确保数据传输的安全性。文中还详细描述了HTTP请求方法(如GET、POST)、请求与响应头字段、状态码分类及意义,并对比了两者在请求-响应模型中的安全性差异。
999 20
|
10月前
|
安全 网络协议 算法
HTTP/HTTPS与SOCKS5协议在隧道代理中的兼容性设计解析
本文系统探讨了构建企业级双协议隧道代理系统的挑战与实现。首先对比HTTP/HTTPS和SOCKS5协议特性,分析其在工作模型、连接管理和加密方式上的差异。接着提出兼容性架构设计,包括双协议接入层与统一隧道内核,通过协议识别模块和分层设计实现高效转换。关键技术部分深入解析协议转换引擎、连接管理策略及加密传输方案,并从性能优化、安全增强到典型应用场景全面展开。最后指出未来发展趋势将更高效、安全与智能。
466 1
|
网络协议 安全 网络安全
HTTP与HTTPS协议入门
HTTP协议是互联网的基石,HTTPS则是其安全版本。HTTP基于TCP/IP协议,属于应用层协议,不涉及数据包传输细节,主要规定客户端与服务器的通信格式,默认端口为80。
630 25
HTTP与HTTPS协议入门