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


目录
相关文章
|
6天前
|
消息中间件 编解码 网络协议
Netty从入门到精通:高性能网络编程的进阶之路
【11月更文挑战第17天】Netty是一个基于Java NIO(Non-blocking I/O)的高性能、异步事件驱动的网络应用框架。使用Netty,开发者可以快速、高效地开发可扩展的网络服务器和客户端程序。本文将带您从Netty的背景、业务场景、功能点、解决问题的关键、底层原理实现,到编写一个详细的Java示例,全面了解Netty,帮助您从入门到精通。
24 0
|
1月前
|
Java 网络架构 Kotlin
kotlin+springboot入门级别教程,教你如何用kotlin和springboot搭建http
本文是一个入门级教程,介绍了如何使用Kotlin和Spring Boot搭建HTTP服务,并强调了Kotlin的空安全性特性。
58 7
kotlin+springboot入门级别教程,教你如何用kotlin和springboot搭建http
|
19天前
|
关系型数据库 API 数据库
后端开发的艺术:从零到一构建高效服务器
在数字化时代,后端开发是支撑现代互联网应用的基石。本文旨在探讨后端开发的核心概念、关键技术以及如何构建一个高效的服务器。我们将从基础的编程语言选择开始,逐步深入到数据库设计、API开发和性能优化等关键领域。通过实际案例分析,我们将揭示后端开发的复杂性和挑战性,同时提供实用的解决方案和最佳实践。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和启发。
|
1月前
使用Netty实现文件传输的HTTP服务器和客户端
本文通过详细的代码示例,展示了如何使用Netty框架实现一个文件传输的HTTP服务器和客户端,包括服务端的文件处理和客户端的文件请求与接收。
39 1
使用Netty实现文件传输的HTTP服务器和客户端
|
1月前
|
网络安全 Docker 容器
VScode远程服务器之远程 远程容器 进行开发(五)
VScode远程服务器之远程 远程容器 进行开发(五)
27 1
|
14天前
|
存储 Oracle 关系型数据库
oracle服务器存储过程中调用http
通过配置权限、创建和调用存储过程,您可以在Oracle数据库中使用UTL_HTTP包发起HTTP请求。这使得Oracle存储过程可以与外部HTTP服务进行交互,从而实现更复杂的数据处理和集成。在实际应用中,根据具体需求调整请求类型和错误处理逻辑,以确保系统的稳定性和可靠性。
16 0
|
1月前
|
Java PHP
PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。理解其垃圾回收机制有助于开发高效稳定的PHP应用。
【10月更文挑战第1天】PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。其垃圾回收机制包括引用计数与循环垃圾回收,对提升应用性能和稳定性至关重要。本文通过具体案例分析,详细探讨PHP垃圾回收机制的工作原理,特别是如何解决循环引用问题。在PHP 8中,垃圾回收机制得到进一步优化,提高了效率和准确性。理解这些机制有助于开发高效稳定的PHP应用。
44 3
|
23天前
|
NoSQL PHP Redis
布谷语音app源码服务器环境配置及技术开发语言
布谷语音app源码服务器环境配置及技术语言研发。。
|
1月前
|
Kubernetes 网络安全 容器
VScode远程服务器进行开发(三)
VScode远程服务器进行开发(三)
30 0
|
2月前
|
开发者
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
32 1