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


目录
相关文章
|
3月前
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
219 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
1月前
|
存储 人工智能 自然语言处理
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
ChatMCP 是一款基于模型上下文协议(MCP)的 AI 聊天客户端,支持多语言和自动化安装。它能够与多种大型语言模型(LLM)如 OpenAI、Claude 和 OLLama 等进行交互,具备自动化安装 MCP 服务器、SSE 传输支持、自动选择服务器、聊天记录管理等功能。
197 15
ChatMCP:基于 MCP 协议开发的 AI 聊天客户端,支持多语言和自动化安装 MCP 服务器
|
27天前
|
JSON Dart 前端开发
鸿蒙应用开发从入门到入行 - 篇7:http网络请求
在本篇文章里,您将掌握鸿蒙开发工具DevEco的基本使用、ArkUI里的基础组件,并通过制作一个简单界面掌握使用
71 8
|
1月前
|
缓存 负载均衡 监控
HTTP代理服务器在网络安全中的重要性
随着科技和互联网的发展,HTTP代理IP中的代理服务器在企业业务中扮演重要角色。其主要作用包括:保护用户信息、访问控制、缓存内容、负载均衡、日志记录和协议转换,从而在网络管理、性能优化和安全性方面发挥关键作用。
64 2
|
2月前
|
安全 开发工具 Swift
Swift 是苹果公司开发的现代编程语言,具备高效、安全、简洁的特点,支持类型推断、闭包、泛型等特性,广泛应用于苹果各平台及服务器端开发
Swift 是苹果公司开发的现代编程语言,具备高效、安全、简洁的特点,支持类型推断、闭包、泛型等特性,广泛应用于苹果各平台及服务器端开发。基础语法涵盖变量、常量、数据类型、运算符、控制流等,高级特性包括函数、闭包、类、结构体、协议和泛型。
45 2
|
2月前
|
关系型数据库 API 数据库
后端开发的艺术:从零到一构建高效服务器
在数字化时代,后端开发是支撑现代互联网应用的基石。本文旨在探讨后端开发的核心概念、关键技术以及如何构建一个高效的服务器。我们将从基础的编程语言选择开始,逐步深入到数据库设计、API开发和性能优化等关键领域。通过实际案例分析,我们将揭示后端开发的复杂性和挑战性,同时提供实用的解决方案和最佳实践。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和启发。
|
3月前
|
网络安全 Docker 容器
VScode远程服务器之远程 远程容器 进行开发(五)
VScode远程服务器之远程 远程容器 进行开发(五)
76 1
|
2月前
|
存储 Oracle 关系型数据库
oracle服务器存储过程中调用http
通过配置权限、创建和调用存储过程,您可以在Oracle数据库中使用UTL_HTTP包发起HTTP请求。这使得Oracle存储过程可以与外部HTTP服务进行交互,从而实现更复杂的数据处理和集成。在实际应用中,根据具体需求调整请求类型和错误处理逻辑,以确保系统的稳定性和可靠性。
106 0
|
3月前
|
NoSQL PHP Redis
布谷语音app源码服务器环境配置及技术开发语言
布谷语音app源码服务器环境配置及技术语言研发。。
|
3月前
|
Kubernetes 网络安全 容器
VScode远程服务器进行开发(三)
VScode远程服务器进行开发(三)
71 0

热门文章

最新文章