java nio 实现轻量http静态文件服务器,基于selector管理socketchannel、bytebuffer解析请求并零拷贝响应,支持路径校验、mime识别与大文件传输。

Java 用 NIO 实现一个简单的 HTTP 静态文件服务器,核心是用 Selector 管理多个 SocketChannel,配合 ByteBuffer 解析请求、读取文件、构造响应。它不依赖 Tomcat 或 Spring,轻量、非阻塞,适合学习协议和底层 I/O 模型。
监听连接并注册读事件
启动一个 ServerSocketChannel,设为非阻塞,绑定端口,再注册到 Selector 上监听 OP_ACCEPT:
- 调用
serverChannel.configureBlocking(false) - 用
serverChannel.register(selector, SelectionKey.OP_ACCEPT) - 进入
selector.select()循环,有新连接时获取SocketChannel - 把新 channel 设为非阻塞,并注册
OP_READ,附带一个ByteBuffer用于接收请求头(比如 8KB)
解析 HTTP 请求行和路径
收到数据后,从 buffer 中提取请求行(如 GET /index.html HTTP/1.1),提取 URI 路径部分:
- 用
buffer.flip()切换读模式,转成String(注意用StandardCharsets.US_ASCII避免乱码) - 按空格分割,取第二个字段,再用
URLDecoder.decode(path, "UTF-8")解码(防%20) - 做基础校验:拒绝
..路径穿越(如/../etc/passwd),只允许子路径访问指定根目录(如./www) - 拼出完整文件路径:
Paths.get("www", decodedPath).toFile()
异步读取文件并写回响应
找到文件后,用 FileChannel 配合 DirectByteBuffer 零拷贝发送(或分块发送大文件):
- 检查文件存在且是普通文件,获取长度,设置响应状态码(200 / 404 / 403)
- 构造响应头(
HTTP/1.1 200 OK\r\nContent-Length: ...\r\nContent-Type: ...\r\n\r\n),写入一个 header buffer - 打开
FileChannel,注册OP_WRITE,把 header buffer 和文件内容分阶段写入 socket channel - 若一次没写完,保留未写完的 buffer,下次
OP_WRITE就绪时继续;写完后关闭 channel
处理常见边界情况
简单但健壮的实现需覆盖几个关键点:
- 请求不完整(buffer 满了还没遇到
\r\n\r\n):扩容 buffer 或丢弃连接 - 大文件超过内存:不要一次性 load 到 heap,用
transferTo()直接由内核传输 - 并发连接数多:每个连接只占少量堆内存(一个 buffer + key attachment),比 BIO 省资源
- 静态资源类型:根据后缀判断 MIME 类型(
.html→text/html、.js→application/javascript)
不复杂但容易忽略细节。写好后用 curl http://localhost:8080/index.html 或浏览器直接访问测试即可。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











