TIL:无需 curl,使用 Bash /dev/tcp 发出 HTTP 请求

Hacker News Top 工具

摘要

了解如何使用 Bash 内置的 /dev/tcp 功能从容器中发出 HTTP 请求而无需 curl 或 wget,适用于受限环境下的轻量级调试。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/06/16 17:34

# 在没有 curl 的容器中,使用 bash 的 /dev/tcp 发起 HTTP 请求 来源:https://mareksuppa.com/til/bash-dev-tcp-http-without-curl/ 我需要检查一个容器能否通过内部 Docker 网络访问另一个容器:只需对共享网络上的服务发起一个简单的 `GET /health` 请求。明显的方法是 `curl http://service:8642/health`。但这个应用镜像非常精简,没有 `curl` 或 `wget`,也没有其他可以用来打开套接字的工具。 结果发现,`bash` 自己就能处理 HTTP。手动打开到主机和端口的连接,然后写入请求,只需要已有的 shell 即可: bash `` exec 3<>/dev/tcp/service/8642 printf 'GET /health HTTP/1.1\r\nHost: service\r\nConnection: close\r\n\r\n' >&3 cat <&3 `` 这里的 `service` 只是你要连接的主机名。它必须能够解析,并且从运行命令的位置能够到达,因此需要事先配置好:可以是 Docker 网络中的容器名或服务名,也可以是任何可解析的 DNS 名称。请替换为你自己的主机和端口。 这会打印出完整的响应:状态行、头、空行以及主体。要添加一个头(例如 `Authorization: Bearer` 令牌),只需要在终止请求的空行之前再添加一行以 `\r\n` 结尾的行即可: bash `` exec 3<>/dev/tcp/service/8642 printf 'GET /v1/models HTTP/1.1\r\nHost: service\r\nAuthorization: Bearer %s\r\nConnection: close\r\n\r\n' "$API_KEY" >&3 cat <&3 `` 我第一次使用时遇到的问题是 `/dev/tcp` 并不是真正的设备文件。磁盘上没有这样的路径;`ls /dev/tcp` 什么都找不到,从另一个 shell 执行 `cat /dev/tcp/...` 只会报错。这是 `bash` 内部处理的一种重定向。来自 [Bash 手册](https://www.gnu.org/software/bash/manual/bash.html#Redirections): > `/dev/tcp/host/port` – 如果 host 是有效的主机名或互联网地址,且 port 是整数端口号或服务名,bash 会尝试打开对应的 TCP 套接字。 之所以选择这个名字,是因为(根据 https://www.gnu.org/software/bash/manual/bash.html#Redirections)没有真正的 Unix 系统存在 `/dev/tcp` 或 `/dev/udp` 目录结构,因此不会发生冲突。Bash 会为你进行 DNS 查找和 `connect(2)` 调用,`exec 3<>` 将套接字分配为文件描述符(`3`),你可以像读写其他文件描述符一样读写它。 几点需要注意: - `Connection: close` 头部很重要。如果没有它,服务器会在响应后保持连接打开(这是 HTTP/1.1 的默认行为),`cat <&3` 会永远等待永远不会到来的字节。请求服务器关闭连接意味着 `cat` 会读到文件结尾并返回。将调用包装在 `timeout 6 bash -c '...'` 中可以应对两种情况。 - 没有 TLS。`/dev/tcp` 打开的是原始套接字,因此这只适用于明文 HTTP。对于 `https`,你需要 `openssl s_client`,既然如此,倒不如直接用合适的工具了。 - 这是 `bash` 的特性,不是 POSIX 标准。`dash`(Debian 的 `/bin/sh`)和 `zsh` 没有这个功能,所以 `#!/bin/sh` 脚本无法使用。请直接调用 `bash`。 - 这是一个编译时选项,当 `bash` 编译时启用了 `--enable-net-redirections` 才生效。大多数主流构建都启用了它,在我使用的基于 Debian 的镜像中它也能正常工作,但 Debian 曾多年禁用它(参见 https://bugs.launchpad.net/ubuntu/+source/bash/+bug/215034),因此在旧版或非常精简的系统上,最好先确认一下。 对于日常工作,`curl` 仍然是正确的工具。但在一个故意设计得非常小巧、无法安装任何东西的容器中,这个方法可以在不添加包的情况下快速完成检查。

相似文章

通过SSH实时查看CI日志

Lobsters Hottest

本文介绍了一项新功能,用户可以通过终端用户界面通过SSH实时查看CI日志,无需安装,并能正确处理ANSI代码。

使用 Go 的 net/http/httptrace 追踪 HTTP 请求

Hacker News Top

本文介绍了如何使用 Go 的 net/http/httptrace 包通过基于上下文的钩子追踪 HTTP 请求阶段(DNS、连接、TLS 等),并演示了构建 CLI 追踪工具和 RoundTripper 日志记录器。