当前位置: 首页 > news >正文

netty构建http服务器

Netty 是一个高性能的异步事件驱动的网络应用框架,用于快速开发可维护的高性能协议服务器和客户端。要使用 Netty 搭建一个支持 HTTP 方法(GET, POST, PUT, DELETE)的 HTTP 服务器,可以按照以下步骤进行操作。

准备工作

  1. 添加依赖:确保你的项目中包含了 Netty 的相关依赖。
  2. Java版本:确保你使用的 Java 版本支持 Netty,一般推荐使用 Java 8 或更高版本。

添加 Maven 依赖

在你的 pom.xml 文件中添加以下依赖:

<dependencies><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.95.Final</version></dependency>
</dependencies>

创建 HTTP 服务器

下面是一个简单的示例,展示了如何创建一个支持 GET, POST, PUT, DELETE 方法的 HTTP 服务器。

1. 定义 HTTP 请求处理器
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {if (!req.decoderResult().isSuccess()) {sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));return;}// 根据请求类型处理switch (req.method()) {case GET:handleGet(ctx, req);break;case POST:handlePost(ctx, req);break;case PUT:handlePut(ctx, req);break;case DELETE:handleDelete(ctx, req);break;default:sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.METHOD_NOT_ALLOWED));break;}}private void handleGet(ChannelHandlerContext ctx, FullHttpRequest req) {// 处理 GET 请求FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.copiedBuffer("This is a GET response", CharsetUtil.UTF_8));sendHttpResponse(ctx, req, response);}private void handlePost(ChannelHandlerContext ctx, FullHttpRequest req) {// 处理 POST 请求FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.copiedBuffer("This is a POST response", CharsetUtil.UTF_8));sendHttpResponse(ctx, req, response);}private void handlePut(ChannelHandlerContext ctx, FullHttpRequest req) {// 处理 PUT 请求FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.copiedBuffer("This is a PUT response", CharsetUtil.UTF_8));sendHttpResponse(ctx, req, response);}private void handleDelete(ChannelHandlerContext ctx, FullHttpRequest req) {// 处理 DELETE 请求FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.copiedBuffer("This is a DELETE response", CharsetUtil.UTF_8));sendHttpResponse(ctx, req, response);}private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {if (res.status().code() != 200) {ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);res.content().writeBytes(buf);buf.release();HttpHeaders.setContentLength(res, res.content().readableBytes());}// Generate an error page if response status code is not 200 (OK).if (res.status().code() != 200) {ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);res.content().writeBytes(buf);buf.release();}// Send the response and close the connection if necessary.ChannelFuture f = ctx.channel().writeAndFlush(res);if (!HttpHeaders.isKeepAlive(req) || res.status().code() != 200) {f.addListener(ChannelFutureListener.CLOSE);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}
2. 启动服务器
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;public class HttpServer {public static void main(String[] args) throws InterruptedException {int port = 8080; // 选择一个端口EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new HttpServerInitializer());ChannelFuture f = b.bind(port).sync();System.out.println("HTTP server started on port " + port);f.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}
}
3. 初始化 Channel
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p = ch.pipeline();p.addLast(new HttpResponseEncoder());p.addLast(new HttpRequestDecoder());p.addLast(new HttpObjectAggregator(65536));p.addLast(new HttpServerHandler());}
}

以上代码提供了一个基本的 HTTP 服务器框架,你可以根据需要添加具体的业务逻辑处理,如错误处理、日志记录、文件上传等高级功能。

在 Netty 中处理文件上传通常涉及到对 HTTP 请求中的 multipart/form-data 类型的解析。这种类型的请求通常用于上传文件和其他表单数据。下面介绍如何使用 Netty 和第三方库来处理文件上传。

第三方库

对于文件上传的支持,我们可以使用 netty-http2 项目中的 netty-codec-http2 依赖或者使用 netty-file-upload 项目中的 netty-codec-http 依赖,后者提供了更直接的方式来处理文件上传。我们将使用 netty-codec-http 依赖。

首先,在你的 pom.xml 文件中添加如下依赖:

<dependencies><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.95.Final</version></dependency><dependency><groupId>io.netty</groupId><artifactId>netty-codec-http</artifactId><version>4.1.95.Final</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version></dependency>
</dependencies>

文件上传处理

  1. HTTP 请求解析器:使用 HttpDataFactoryHttpPostRequestDecoder 解析上传的数据。
  2. 文件保存:定义一个方法来保存上传的文件。
更新 HttpServerHandler
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {if (!req.decoderResult().isSuccess()) {sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));return;}switch (req.method()) {case GET:handleGet(ctx, req);break;case POST:handlePost(ctx, req);break;case PUT:handlePut(ctx, req);break;case DELETE:handleDelete(ctx, req);break;default:sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.METHOD_NOT_ALLOWED));break;}}private void handlePost(ChannelHandlerContext ctx, FullHttpRequest req) {if (!req.headers().contains(HttpHeaderNames.CONTENT_TYPE)) {sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));return;}String contentType = req.headers().get(HttpHeaderNames.CONTENT_TYPE);if (contentType.contains("multipart/form-data")) {handleFileUpload(ctx, req);} else {handleRegularPost(ctx, req);}}private void handleFileUpload(ChannelHandlerContext ctx, FullHttpRequest req) {FileUpload fileUpload = new FileUpload(new DiskFileItemFactory());HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(fileUpload, req);while (true) {try {HttpPostRequestDecoder.State state = decoder.decode(ctx.channel(), req, ctx.alloc().buffer());if (state == HttpPostRequestDecoder.State.END_OF_MESSAGE) {break;}if (state == HttpPostRequestDecoder.State.CHUNKED_INPUT) {decoder.offer(req);}} catch (HttpPostRequestDecoder.EndOfDataDecoderException e) {break;} catch (HttpPostRequestDecoder.ErrorDataDecoderException e) {sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));return;}}FileItemIterator iterator = decoder.getBodyHttpData();while (iterator.hasNext()) {FileItemStream item = iterator.next();if (item.isFormField()) {// Handle form fields here} else {saveUploadedFile(item, "/tmp/uploaded"); // Save the file to disk}}FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.copiedBuffer("File uploaded successfully.", CharsetUtil.UTF_8));sendHttpResponse(ctx, req, response);}private void saveUploadedFile(FileItemStream item, String uploadDir) throws IOException {Path targetPath = Path.of(uploadDir, item.getName());Files.createDirectories(targetPath.getParent());try (FileItemStream.ItemStream stream = item.openStream()) {Files.copy(stream, targetPath, StandardCopyOption.REPLACE_EXISTING);}}private void handleRegularPost(ChannelHandlerContext ctx, FullHttpRequest req) {// Handle regular POST data hereFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.copiedBuffer("This is a POST response", CharsetUtil.UTF_8));sendHttpResponse(ctx, req, response);}private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {// ... [same as before]}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}
}

注意事项

  • 在这个示例中,我们使用了 commons-fileupload 库来处理 multipart/form-data 数据。
  • 上传的文件被保存到 /tmp/uploaded 目录下。你需要确保这个目录存在并且有适当的权限。
  • 我们使用了 DiskFileItemFactoryFileUpload 来处理文件上传。
  • 如果上传的文件非常大,你可能需要调整 DiskFileItemFactory 的配置以适应你的需求。

以上代码提供了一个基本的文件上传处理机制。你可以根据实际需要进一步扩展和优化。例如,可以添加文件大小限制、文件类型检查等功能。

相关文章:

netty构建http服务器

Netty 是一个高性能的异步事件驱动的网络应用框架&#xff0c;用于快速开发可维护的高性能协议服务器和客户端。要使用 Netty 搭建一个支持 HTTP 方法&#xff08;GET, POST, PUT, DELETE&#xff09;的 HTTP 服务器&#xff0c;可以按照以下步骤进行操作。 准备工作 添加依赖…...

Docker中安装Kafka和Kafka UI管理界面

Kafka 简介 Apache Kafka 是一个分布式流处理平台,主要用于构建实时数据管道和流应用。它最初由LinkedIn开发,并于2011年开源,之后成为Apache项目的一部分。Kafka的核心概念和功能包括: 发布与订阅消息系统:Kafka允许用户发布和订阅消息流。高吞吐量:Kafka能够处理大量数…...

防火墙——SNAT和DNAT策略的原理及应用、防火墙规则的备份、还原和抓包

防火墙——SNAT和DNAT策略的原理及应用、防火墙规则的备份、还原和抓包 &#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&…...

C# 冒泡排序

栏目总目录 概念 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;它通过重复遍历待排序的数列&#xff0c;比较每对相邻的项&#xff0c;并在顺序错误时交换它们的位置&#xff0c;直到没有需要交换的项为止。由于排序过程中小数逐渐“浮”到前…...

网络传输层——UDP与TCP

前言&#xff1a; 1.国际网络体系结构&#xff1a; OSI模型: open system interconnect 理论模型 1977 国际标准化组织 各种不同体系结构的计算机能在世界范围内互联成网。 应用层:要传输的数据信息&#xff0c;如文件传输&#xff0c;电子邮件等…...

Hype 4 Pro for Mac:专业级HTML5动画制作利器

Hype 4 Pro for Mac是一款专为Mac用户设计的专业级HTML5动画制作软件&#xff0c;它集动画制作、交互设计于一身&#xff0c;为用户提供了一种全新的、高效的动画制作体验。 该软件拥有直观易用的界面和强大的功能&#xff0c;支持多种设计元素&#xff0c;如滚动、旋转、缩放…...

C++ STL remove, remove_if 用法

一&#xff1a;功能 移除序列中&#xff08;满足给定条件&#xff09;的元素&#xff0c;该操作并不是真的将元素删除&#xff0c;而是序列的size不变&#xff0c;只是更新了迭代器&#xff0c;该函数会返回最后一个未删除元素的位置。 二&#xff1a;用法 #include <vect…...

HarmonyOS NEXT 开发之ArkTS基础入门

ArkTS 是 HarmonyOS NEXT 的开发语言&#xff0c;它基于 TypeScript 并进行了扩展和优化。以下是一些基础语法知识点、示例用法及注意事项。 一、ArkTS 简介 ArkTS 是一种基于 TypeScript 的编程语言&#xff0c;主要用于 HarmonyOS 应用的 UI 界面和业务逻辑开发。它在 Type…...

UE5 C++跑酷练习(Part2)

一.首先GameMode里有Actor数组&#xff0c;组装直线路&#xff0c;和左右路 #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "RunGANGameMode.generated.h"UCLASS(minimalapi) class ARunGANGameMode : public AG…...

从0开始搭建vue + flask 旅游景点数据分析系统(二):搭建基础框架

这一期目标是把系统的布局给搭建起来&#xff0c;采用一个非常简单的后端管理风格&#xff0c;可以参考官方的页面 https://element.eleme.cn/#/zh-CN/component/container 下面我们开始搭建&#xff0c;首先&#xff0c;安装一下vue-router&#xff0c;element-ui npm insta…...

【过滤器 vs 拦截器】SpringBoot中过滤器与拦截器:明智选择的艺术(如何在项目中做出明智选择)

文章目录 SpringBoot 过滤器 vs 拦截器过滤器 (Filter)定义特点使用场景实现步骤创建过滤器类注册过滤器&#xff08;可选&#xff0c;如果不使用 WebFilter 注解&#xff09; 拦截器 (Interceptor)定义特点使用场景实现步骤创建拦截器类注册拦截器 过滤器与拦截器的比较实际项…...

2024-06学习笔记

1.事务与数据库链接的占用 如果用Transactional注解&#xff0c;那在第一次与数据库交互的时候&#xff0c;就会打开数据库链接&#xff0c;再整个方法执行完&#xff0c;才会关闭数据库链接。 即使后边用的事务传播是required_new,那之前的事务也是被挂起&#xff0c;不会被…...

【VUE】封装一个追随鼠标的漂浮组件框架

红色箭头代表鼠标位置&#xff0c;蓝色区域跟随鼠标出现&#xff0c;鼠标进行其他操作的时候&#xff0c;蓝色区域隐藏。 vue全码 <template><divmousemove"updatePosition"mouseleave"hideDiv"class"container":style"{ positi…...

mapstruct与lombok结合使用

问题 如果同时使用mapstruct与lombok&#xff0c;需要多添加一个lombok支持mapstruct的依赖库。 解决 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId> </dependency><dependency><groupId&…...

【SpringBoot】Web开发之URL映射

RequestMapping("/getDataById/{id}") public String getDataById(PathVariable("id") Long id){ return "getDataById:"id; }46 如果URL中的参数名称与方法中的参数名称一致&#xff0c;则可以简化为&#xff1a; RequestMapping("/get…...

对递归的一些理解。力扣206题:翻转链表

今天在刷力扣的时候&#xff0c;在写一道翻转链表的题目的过程中&#xff0c;在尝试使用递归解决该问题的时候&#xff0c;第一版代码却每次都返回的是null&#xff0c;这个错误让我尝试去debug了一下&#xff0c;最终找出了问题&#xff0c;并且让我对递归有了一些更深的理解&…...

Kafka面试三道题

针对Kafka的面试题&#xff0c;从简单到困难&#xff0c;我可以给出以下三道题目&#xff1a; 1. Kafka的基本概念与优势 问题&#xff1a;请简要介绍Kafka是什么&#xff0c;并说明它相比传统消息队列的优势有哪些&#xff1f; 答案&#xff1a; Kafka定义&#xff1a;Apa…...

C/C++编程-算法学习-数字滤波器

数字滤波器 一阶低通滤波器结论推导11. 基本公式推导2. 截止频率 和 采样频率 推导 实现 二阶低通滤波器实现1实现2 一阶低通滤波器 结论 其基本原理基于以下公式&#xff1a; o u t p u t [ n ] α ∗ i n p u t [ n ] ( 1 − α ) ∗ o u t p u t [ n − 1 ] output[n] …...

maven介绍 搭建Nexus3(maven私服搭建)

Maven是一个强大的项目管理工具&#xff0c;它基于项目对象模型&#xff08;POM&#xff1a;Project Object Model&#xff09;的概念&#xff0c;通过XML格式的配置文件&#xff08;pom.xml&#xff09;来管理项目的构建 Maven确实可以被视为一种工程管理工具或项目自动化构…...

电商项目之如何判断线程池是否执行完所有任务

文章目录 1 问题背景2 前言3 4种常用的方法4 代码4.1 isTerminated()4.2 线程池的任务总数是否等于已执行的任务数4.3 CountDownLatch计数器4.4 CyclicBarrier计数器 1 问题背景 真实生产环境的电商项目&#xff0c;常使用线程池应用于执行大批量操作达到高性能的效果。应用场景…...

Cursor智能体工具包:从代码助手到自主编程代理的进化

1. 项目概述&#xff1a;从“智能代码补全”到“自主编程代理”的进化如果你和我一样&#xff0c;在过去一两年里深度使用过Cursor&#xff0c;那么你对它的第一印象大概率是“一个集成了AI的现代化代码编辑器”。它确实把智能代码补全、聊天式编程和代码理解做到了一个新高度&…...

2026在线去水印工具怎么用?免费视频去水印网站和本地水印去除方法推荐

引言 在日常工作和生活中&#xff0c;用户常常需要处理带有水印的视频文件。无论是出于内容二次创作、视频编辑还是个人使用的需求&#xff0c;去除视频水印成为了一个普遍的技术需求。2026年&#xff0c;随着在线视频处理工具的发展&#xff0c;多种去水印解决方案应运而生&am…...

自托管项目管理与知识库系统:基于文件存储的轻量级解决方案

1. 项目概述与核心价值最近在折腾个人知识库和项目管理工具&#xff0c;发现很多现成的方案要么太重&#xff0c;要么太轻&#xff0c;要么就是配置起来让人头大。直到我遇到了一个叫bicodeurubu/pm-wiki-v2的项目&#xff0c;它给我的第一印象是“清爽”。这其实是一个基于现代…...

JAVA摄影约拍线上预约系统源码的预约流程

&#x1f4f8; JAVA摄影约拍线上预约系统 — 完整预约流程&#xff08;源码级拆解&#xff09;&#x1f5fa;️ 整体预约流程图&#xff08;一张图看懂&#xff09;用户端&#xff08;小程序/H5&#xff09; Java后端&#xff08;Spring Boot&#xff09; …...

英雄联盟智能助手:3分钟上手,让你的游戏体验提升300%

英雄联盟智能助手&#xff1a;3分钟上手&#xff0c;让你的游戏体验提升300% 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power &#x1f680;. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄选择犹…...

从手忙脚乱到一键连招:用GSE重新定义你的魔兽世界战斗体验

从手忙脚乱到一键连招&#xff1a;用GSE重新定义你的魔兽世界战斗体验 【免费下载链接】GSE-Advanced-Macro-Compiler GSE is an alternative advanced macro editor and engine for World of Warcraft. 项目地址: https://gitcode.com/gh_mirrors/gs/GSE-Advanced-Macro-Co…...

Go语言ARP工具包:从协议原理到网络诊断实战

1. 项目概述&#xff1a;一个被低估的网络诊断利器 如果你在运维、网络安全或者仅仅是喜欢折腾家庭网络的圈子里混过一段时间&#xff0c;大概率听说过或者用过 arp 命令。但大多数人&#xff0c;包括很多从业者&#xff0c;对它的认知可能还停留在“查看IP和MAC地址对应关系…...

基于MCP协议为AI智能体赋予本地桌面自动化能力

1. 项目概述&#xff1a;为AI智能体赋予“手和眼”的桌面操作技能如果你正在使用像Cursor、Claude Code或Codex这类AI编程助手&#xff0c;可能会发现一个痛点&#xff1a;它们能帮你写代码、分析问题&#xff0c;但无法直接操作你的电脑。你想让它帮你打开一个软件、填写一个表…...

基于RAG与本地化部署的Obsidian智能知识库助手实战指南

1. 项目概述&#xff1a;当知识管理遇上AI副驾驶如果你和我一样&#xff0c;常年泡在Obsidian这个知识管理的“第二大脑”里&#xff0c;那你一定对那种感觉不陌生&#xff1a;笔记越积越多&#xff0c;知识网络越来越复杂&#xff0c;但当你真正需要调用某个信息、串联某个想法…...

5分钟掌握rpatool:解锁Ren‘Py游戏资源的完整指南

5分钟掌握rpatool&#xff1a;解锁RenPy游戏资源的完整指南 【免费下载链接】rpatool (migrated to https://codeberg.org/shiz/rpatool) A tool to work with RenPy archives. 项目地址: https://gitcode.com/gh_mirrors/rp/rpatool 想象一下&#xff0c;你正在探索一个…...