计网课本里,应用层一口气列了十几种协议。
我学了两年Java,以为只有HTTP/HTTPS是"常客",其余都是"路人"。
直到线上域名解析失败导致整个微服务挂掉、对接老旧系统被迫翻出FTP文档、用SSH端口转发救火......
我才发现:它们一直在我的代码和运维里默默出镜,只是我从未认真打过招呼。
这篇文章,我从一个Java后端学习者的真实经历 出发,重新认识应用层这五位"老熟人"------
HTTP/HTTPS、DNS、FTP、SSH 。
不讲八股,只讲它们什么时候出现在我的项目里、出了什么bug、以及我现在怎么和它们相处。

📦 一、HTTP/HTTPS:一日三餐,但你真的嚼透了吗?
1.1 我在项目里和HTTP打了多少照面?
-
@RestController返回 JSON → 客户端用 HTTP 拿到数据 -
Feign 调另一个微服务 → HTTP 请求
-
RestTemplate 调支付宝/微信/高德地图 API → HTTP
-
Nginx 反向代理 → 转发的也是 HTTP
可以说,没有 HTTP,现代 Java Web 开发直接瘫痪。
1.2 一个让我改了一晚上bug的报文细节
有次在"知识汇"教育平台里,前端同事说"登录接口偶尔返回 400"。
我抓包看到请求报文:
html
POST /login HTTP/1.1
Host: api.zhihui.com
Content-Type: application/x-www-form-urlencoded
username=admin&password=123456
而我后端期待的是 JSON。
错误码 400 Bad Request 就是客户端发的东西服务端看不懂。
从那以后,我死死记住了:HTTP 报文的结构 + Content-Type 必须匹配。
请求报文(简化版):
html
方法 路径 版本
头部: 值
主体(可选)
响应报文:
html
版本 状态码 短语
头部: 值
主体
状态码我排错时最常用:
-
200 OK → 一切正常
-
301/302 → 重定向(比如支付成功后跳转)
-
400 → 客户端请求格式有误
-
401 → 没登录
-
403 → 没权限
-
404 → 接口地址写错了
-
429 → 被限流了(秒杀场景常见)
-
500 → 后端代码异常(空指针之类的)
-
503 → 服务熔断或不可用
1.3 HTTPS = HTTP + 一件防弹衣
HTTPS 就是在 HTTP 外面套了一层 TLS/SSL 。
它在 Java 开发里的体现:
-
用
RestTemplate调https://接口,默认会自动验证证书。 -
本地自签名证书要跳过校验(写测试代码时常用,但生产环境绝对不能干)。
一句话:HTTP 是裸奔,HTTPS 是穿了防弹衣。
1.4 关于 HTTP/2 和 HTTP/3
我只在配置 Nginx 时打开过 http2,发现多个请求可以复用同一个连接,速度快了不少。
至于 HTTP/3(底层用 UDP),目前还是前沿玩具,但面试官喜欢问,知道它"解决了队头阻塞"就够了。
📁 二、FTP:那个我以为灭绝了,结果项目里真遇到了的协议
2.1 它居然还在用?
大二做课设的时候,老师说"用 FTP 上传文件"。我心想:这什么上古技术?
后来实习时,对接某银行的对账系统,对方接口文档写着:通过 FTP 下载对账单 。
我懵了------FTP 还活着。
2.2 主动模式 vs 被动模式:我踩过的坑
第一次用 FTPClient 连接对方服务器,一直超时。
查了半天,原来是防火墙拦截了主动模式 。
解决方案:在 Java 代码里开启被动模式。
java
FTPClient ftp = new FTPClient();
ftp.connect(host, port);
ftp.login(user, pass);
ftp.enterLocalPassiveMode(); // ← 这一行救了我
后来我理解了:
-
主动模式:服务器主动连客户端的一个随机端口(容易被防火墙拦)
-
被动模式:客户端去连服务器打开的一个随机端口(更通用)
给 Java 学生的建议:如果对接 FTP,上来就开被动模式,省去 90% 的排错时间。
🔍 三、DNS:互联网的电话本,崩一次你就知道它多重要
3.1 它每天都在为你工作,你却几乎忘了它
浏览器输入 www.baidu.com 能打开,全靠 DNS 把这个名字翻译成 IP 地址。
Java 里解析域名就是一行:
java
InetAddress ip = InetAddress.getByName("www.baidu.com");
System.out.println(ip.getHostAddress()); // 打印 110.242.68.66
3.2 一次 DNS 故障让我通宵排查
在"智答知识库"项目里,我用 Docker Compose 启动 Java + Python 两个容器。
Java 容器里通过 python-api:8000 访问 Python 服务,有时候突然连不上。
重启容器又好了,随机复现。
查了两小时,发现是 Docker 内置 DNS 偶尔解析失败 。
解决方案:把两个容器放进同一个自定义网络,并加上 --link 或者用 depends_on。
从那以后,我记住了 DNS 解析是有缓存、有超时、有失败可能的 。
微服务架构里不要频繁做域名解析,最好用 IP 或长连接。
开发中常见 DNS 问题:
-
DNS 污染/劫持 → 换公共 DNS(
114.114.114.114或8.8.8.8) -
DNS 解析延迟 → 启用缓存或用 IP 直连
-
内网 DNS → 公司内部
.local域名需要自建 DNS 或改 hosts
🔐 四、SSH:不只是 ssh root@server
4.1 你以为 SSH 只用来登录服务器?
我最早用 SSH 就是 ssh user@host 连服务器部署 Jar 包。
后来学到它还能:
-
执行远程命令 :
ssh root@server "systemctl restart java-app" -
端口转发 :把远程服务器的 8080 端口映射到本地,直接
localhost:8080就能访问远程 SpringBoot 应用 -
Git over SSH :
git@github.com:xxx/xxx.git用的就是 SSH -
SFTP:安全的文件传输,比 FTP 安全得多
4.2 一个让我觉得"SSH 太强了"的场景
有一次线上服务器只开了 22 端口(SSH),但我想访问它上面的一个 Web 服务(8080)。
用了这条命令:
java
ssh -L 8080:localhost:8080 root@server
然后我打开本地浏览器输入 http://localhost:8080,就看到了远程服务器的网页。
这就是 SSH 本地端口转发------开发调试神器。
4.3 Java 里调用 SSH
可以用 JSch 库执行远程命令:
java
JSch jsch = new JSch();
Session session = jsch.getSession("user", "host", 22);
session.setPassword("pass");
session.connect();
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand("ls -la");
channel.connect();
// 读取输出...
不过日常开发中,我们更多是用 Git over SSH(配密钥),或者 Gradle/Maven 插件通过 SSH 部署。
📋 五、一张表总结:这些协议到底什么时候会出现在我的 Java 项目里?

我的感悟 :
HTTP 是主角,但配角一个都不能少。
面试官问"应用层有哪些协议",别只背名字,像我一样说出来:
"我在知识汇项目里用 Feign 调 HTTP 接口;对接银行时用 FTPClient 被动模式拉账单;线上 DNS 崩过一次,后来加了缓存;我用 SSH 端口转发调试过远程服务......"
这比任何八股答案都值钱。