这是一个基于 TCP 自实现 HTTP 协议栈的 简易 HTTP 服务器与客户端 项目,包含:
- HTTP 服务器端:监听端口、解析 HTTP 请求、路由分发、静态文件服务、用户注册/登录/鉴权、文档目录访问/上传。
- HTTP 客户端 CLI:基于 TCPClient 与 HTTP 协议构造请求、处理 301/302/304 等状态码、实现简单缓存与重定向、提供交互式命令行操作。
- 命令行框架:封装通用 CLI 基类与命令解析能力,支持历史记录、帮助等。
项目核心目标是:在不依赖现成 Web 框架的前提下,从 TCP 层手写一个可工作的 HTTP 客户端/服务器与用户/文件服务系统。
- JDK:11 及以上(
pom.xml指定maven.compiler.source/target为 11)。 - 构建工具:Maven 3.x。
- 依赖库(由maven自动导入):
commons-cli:1.4:命令行参数解析。jline:3.25.0:交互式终端与历史记录。org.json:20231013:JSON 支持。org.fusesource.jansi:2.4.0(scope=provided):与 jline 配合,为 Windows 等终端提供 ANSI 颜色/样式支持。jna:5.13.0:与 jline 配合,为类 Unix 系统(Linux/macOS)终端提供本地特性支持(如终端能力探测等)。
操作系统不限(Windows / Linux / macOS 皆可),示例中的路径以当前工作目录为准。
在项目根目录(包含 pom.xml 的目录)打开终端,首先执行打包命令:
mvn clean package该命令会先清理再编译,并在 target/ 目录下生成 web-1.0-SNAPSHOT.jar 以及编译好的 classes 等产物,供后续运行使用。
在同一目录下,根据操作系统使用 Maven 的 exec:java 目标启动客户端主类 CLI.client.HTTPClientCLI。
- Windows(PowerShell / CMD)
mvn exec:java "-Dexec.mainClass=CLI.client.HTTPClientCLI"- macOS / Linux(Bash 等)
mvn exec:java -Dexec.mainClass='CLI.client.HTTPClientCLI'执行成功后,会进入交互式 HTTP 客户端:
=====simple http client=====
Client>
如果需要本地运行 HTTP 服务器,只需将 exec.mainClass 替换为服务器端的主类 CLI.server.HTTPServerCLI,分别在不同系统下执行:
- Windows
mvn exec:java "-Dexec.mainClass=CLI.server.HTTPServerCLI"- macOS / Linux
mvn exec:java -Dexec.mainClass='CLI.server.HTTPServerCLI'启动后,终端中会看到类似输出,说明服务器已在 8019 端口 监听:
=====simple http server=====
server started on port: 8019
此时可以在另一终端窗口按前述方式启动客户端 CLI,与本地 HTTP 服务器进行交互。
本项目的 HTTP 服务器已部署在远程服务器上,IP 地址为 140.210.142.61,端口为 8019。
在本地按照第 2 节方式启动客户端 CLI 后,可以直接通过以下命令连接并操作远程服务器:
Client> enter http://140.210.142.61:8019/
后续即可在该连接上继续使用 enter / refresh / fetch / push / login / register / logout 等命令,与远程服务端进行交互。
使用终端的建议与已知限制
- 优先在系统终端/IDE“终端”面板中使用上述命令运行,以获得最完整的交互体验(含历史记录、正常行编辑/光标行为)。
- IDE 相关区别:
- IDE 一键运行(Run/Debug 按钮):可执行程序并能进行登录/注册等交互,但在该控制台中 密码输入无法隐藏(会回显),且 命令历史不可用(上下键通常仅做光标移动)。
- 本 CLI 目前仅提供历史记录功能,没有颜色控制、没有 Tab 补全。
历史记录使用提示
- 历史文件:
.history/http-client-history.txt(客户端)/.history/http-server-history.txt(服务器),在系统终端与大多数 IDE 终端面板中可跨会话持久。- 基本浏览:直接按 ↑/↓ 逐条查看历史,回车执行。
- 前缀过滤:先输入前缀(如输入
ent),再按 ↑,只会出现以该前缀开头的历史命令(如各类enter ...),便于快速定位。- 适用范围:历史记录在 系统终端 与 IDE 的终端面板 中可用;在 IDE 的一键运行(Run/Debug)控制台 中通常不可用或行为异常(上下键仅移动光标)。
网络波动与 “transmission failed” 处理提示
- 如遇
transmission failed,请参阅文档中的 “项目限制与已知问题” 节以获取可能原因与排查建议。
下面分别介绍 HTTP 客户端 CLI 和 HTTP 服务器 CLI 的命令。
所有命令都支持 -h / --help 查看自身详细说明。
-
help- 功能:显示所有可用命令及其简要说明。
- 用法:
help
-
exit- 功能:退出客户端程序。若当前已登录,会先自动登出并关闭与服务器的连接。
- 用法:
exit
-
enter- 功能:访问页面或在目录中导航。支持三种使用模式:
- 首次连接:
enter <url>建立到服务器的连接(如enter http://127.0.0.1:8019/) - 目录前进:
enter -f <path>在当前目录下进入子路径(如当前在/document/,执行enter -f subfolder会访问/document/subfolder) - 目录后退:
enter -b回退到上一级目录
- 首次连接:
- 选项:
-f <path>/--forward <path>:相对当前路径前进到指定子路径-b/--back:后退到上一级目录-r/--root:以 root 权限访问(若使用此选项需有有效的 root token)
- 约束:
-f和-b不能同时使用- 使用完整 URL 时,若未连接会自动建立连接
- 功能:访问页面或在目录中导航。支持三种使用模式:
-
refresh- 功能:重新加载当前页面(重新向服务器请求当前路径)。
- 用法:
refresh或refresh -r(以 root 权限刷新) - 选项:
-r/--root:以 root 权限重新加载
- 前置条件:必须已建立连接且访问过至少一个页面
-
fetch- 功能:从服务器下载单个文件到本地缓存目录(
.cache/)。 - 用法:
fetch <filename>或fetch -r <filename>(以 root 权限下载) - 选项:
-r/--root:以 root 权限下载
- 限制条件:
- 仅在
/document路径下可用,其他路径会提示不可用 - 只能下载文件,不能是包含路径分隔符
/的表达式 - 文件保存在
.cache/目录中供后续操作使用
- 仅在
- 功能:从服务器下载单个文件到本地缓存目录(
-
push- 功能:从本地缓存目录(
.cache/)上传文件到服务器的指定目录。 - 用法:
push <filepath> <remote_dir>:上传本地文件到服务器当前路径/<remote_dir>下。<filepath>必须是本地文件的相对路径或绝对路径,不能仅传入文件名。相对路径默认以客户端当前工作目录为准(客户端默认工作目录为.cache/)。<remote_dir>只支持相对路径(如.、subfolder、../other等)
- 选项:
-r/--root:以 root 权限上传
- 使用示例:
- 当前在
/document/,执行push ./photo.jpg .会将客户端当前工作目录下的./photo.jpg(通常为.cache/photo.jpg)上传到服务器的/document/photo.jpg。 - 执行
push ./photo.jpg subfolder会上传到/document/subfolder/photo.jpg。
- 当前在
- 限制条件:
- 仅在
/document路径下可用 - 上传后服务器返回该目录的最新内容
- 仅在
- 功能:从本地缓存目录(
-
login- 功能:使用用户名和密码登录服务器,获取 token 用于身份验证。
- 用法:
login - 交互过程:
- 提示输入用户名,密码不回显(隐藏显示)
- 登录失败可重试,最多 3 次
- 成功结果:
- 服务器返回 token,客户端自动保存
- 后续访问文档空间时会自动使用该 token 进行身份验证
- 可以访问自己的私有文档空间
- 常见错误:
- 用户不存在
- 密码错误
- 用户已在其他客户端登录
-
register- 功能:注册新用户账户,同时为该用户初始化文档空间。
- 用法:
register - 交互过程:
- 提示输入用户名
- 提示输入密码(不回显)
- 提示确认密码(必须与第一次输入相同)
- 最多允许重试 3 次
- 成功结果:
- 用户账户创建成功
- 服务器自动为该用户创建专属的文档空间
- 可立即使用该账户登录
- 常见错误:
- 用户名已存在
- 用户名或密码不符合格式要求
- 两次输入的密码不一致
-
logout- 功能:登出当前账户,清除 token 信息。
- 用法:
logout - 结果:
- token 被服务器注销
- 客户端清空本地保存的 token
- 之后访问需要重新登录或以 root 权限进行
- 自动返回到
/login路径
服务器端 CLI 较为简单,当前主要用于查看日志与退出。
-
help- 功能:显示所有可用命令(当前主要是
exit和help)。 - 用法:
help
- 功能:显示所有可用命令(当前主要是
-
exit- 功能:停止 HTTP 服务器并退出进程。
- 用法:
exit
HTTP 服务器采用 透明的用户目录隔离机制,为每个用户提供独立的文件存储空间,确保用户隐私和数据安全。
-
使用体验
- 用户注册后即拥有一个专属的文档空间
- 登录后通过
/document/访问时,会自动访问自己的专属空间 - 用户无需了解自己目录的实际位置,只需正常使用
/document/路径即可 - 用户只能访问自己的文件,无法访问其他用户或系统文件
-
权限隔离
- 不同用户的文档空间完全独立,彼此无法互见
- 普通用户无法越权访问其他用户或系统资源
- 系统保留 root 权限用于管理员操作和系统维护
-
文件操作
- 用户注册时系统自动初始化其文档空间
- 登录后可通过以下操作管理自己的文件:
- 浏览文档空间中的文件和文件夹结构
- 上传新文件到文档空间(
push命令) - 下载文件到本地(
fetch命令)
Root 权限是一种特殊的系统级权限,用于绕过普通用户的访问限制。
-
用途
- 允许具有 root 权限的客户端访问所有用户的文档空间
- 用于系统管理、文件维护、备份等特殊操作
- 通常由系统管理员或具有特殊身份的客户端使用
-
Root Token
- 系统维护一个特殊的
root token,与普通用户 token 独立存储和管理 - 仅有授权的管理员或系统配置中预设的 root token 可用
- 需通过
UserManager中的root token管理机制获取或验证
- 系统维护一个特殊的
-
使用方式
- 在客户端命令中添加
-r或--root标志 - 支持以下命令的 root 权限版本:
enter -r <path>:以 root 权限访问任意路径refresh -r:以 root 权限刷新当前页面fetch -r <filename>:以 root 权限下载文件push -r <filepath> <remote path>:以 root 权限上传文件
- 使用 root 权限时,服务器会通过验证 root token 来授权请求
- 在客户端命令中添加
本项目为教学演示实现,以下为已知限制和使用提示:
-
接收/解析策略:本项目没有实现严格的流式分段解析(streaming);实现上采用“先接收完整报文再解析”的方式以简化代码逻辑。该设计对小/中等大小文件适用,但对大文件传输存在局限性。
-
大文件支持说明:通过调整接收超时设置,实践中已能较稳定地传输约 3MB 左右的图片(视网络与主机性能而定)。对更大的文件不做保证,可能导致传输失败或连接中断。
-
关于 "transmission failed":客户端显示该信息时,常见原因包括但不限于:
- 网络波动或超时;
- 待传输文件过大(超过本实现的接收能力);
- 服务器端内部错误(例如文件系统异常,参见“服务器部署信息”)。
-
调试建议:
- 遇到问题时请先查看部署主机的
server.log(详见“服务器部署信息”),确认是网络问题还是服务器端异常。 - 必要时可在本地运行服务端,以验证是否为网络问题
- 网络波动时应先用
exit命令退出客户端再重新运行,避免传输错位(本轮接收到上一轮的报文)
- 遇到问题时请先查看部署主机的