除了curl实现Http请求,还可以通过 /dev/tcp 进行 HTTP 请求,如果不想将curl安装在一个只运行简单健康检查过程的sidecar容器中。这东西派上用场了
来自rednafi分享:
今天,我学到了 Bash 的一个小技巧,那就是可以使用 /dev/tcp 文件描述符发出原始 HTTP 请求,而无需使用 curl 或 wget 等工具。 这在编写一个需要向服务发出 TCP 请求的健康检查脚本时派上了用场。
下面的脚本打开了一个 TCP 连接,并向 example.com 发送了一个简单的 GET 请求:
#!/bin/bash
# 在 80 端口上打开与 example.com 的 TCP 连接,并分配文件描述符 3 # 执行命令会在整个脚本生命周期内保持 /dev/fd/3 打开 # 3<> 启用双向读写器 exec 3<>/dev/tcp/example.com/80
# 向服务器发送 HTTP GET 请求 # >& 将 stdout 重定向到 /dev/fd/3 echo -e "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n" >&3
# 读取并打印服务器的响应 # <& 将 /dev/fd/3 的输出重定向到 cat cat <&3
#关闭文件描述符,终止 TCP 连接 exec 3>&-
|
运行该脚本将在控制台中打印来自网站的响应。
该代码段首先打开了与 example.com 80 端口的 TCP 连接,并指定文件描述符 3 来管理该连接。 执行程序确保文件描述符 3 在脚本运行期间保持打开状态,这样就可以进行多次读写操作,而无需每次都重新打开连接。
使用文件描述符可以使代码更简洁。 如果没有文件描述符,每次读写操作我们都需要将输入和输出直接重定向到 /dev/tcp/example.com/80,这会使脚本变得更加繁琐和难以阅读。
然后,我们向服务器发送 HTTP GET 请求,并将请求呼应到文件描述符 3。
我们使用 cat <&3 读取并打印服务器的响应,它从文件描述符中读取并将输出打印到控制台。
最后,脚本使用 exec 3>&- 终止文件描述符 3,从而关闭连接。
这是 Bash 特有的技巧,在 Zsh 或 Fish 等其他 shell 中无法使用。 它还允许你以同样的方式打开 UDP 连接。 Bash manpage 是这样解释其用法的:
/dev/tcp/host/port 如果 host 是有效的主机名或互联网地址,port 是整数端口号或服务名,则 bash 会尝试 打开相应的 TCP 套接字。
/dev/udp/host/port 如果 host 是有效的主机名或互联网地址,port 是整数端口号或服务名,则 bash 会尝试 打开相应的 UDP 套接字。
|
我用它编写了下面这个健康检查脚本。 我不想把 curl 安装在一个只运行一个健康检查进程的 sidecar 容器中,这样可以让事情更简单。
#!/bin/bash
#启用 bash 严格模式 set -euo pipefail
# Constants readonly HOST="example.com" readonly PORT=80 readonly HEALTH_PATH="/"
# 打开与指定主机和端口的 TCP 连接 exec 3<>"/dev/tcp/${HOST}/${PORT}"
# Send the HTTP GET request to the server echo -e \ "GET ${HEALTH_PATH} HTTP/1.1\r\nHost: ${HOST}\r\nConnection: close\r\n\r\n" >&3
# Read the HTTP status from the server's response HTTP_STATUS="$(head -n 1 <&3 | awk '{print $2}')" if [[ "${HTTP_STATUS}" == "200" ]]; then echo "Service is healthy." exit 0 else echo "Service is not healthy. HTTP status: ${HTTP_STATUS}" exit 1 fi
# Close the file descriptor, terminating the TCP connection exec 3>&-
|
脚本向服务发出 GET 请求,并检查原始响应的 HTTP 状态是否为 200。
请注意,如果服务返回的是 301 重定向代码,脚本就会失败。
另外,你需要进行原始文本 HTTP 请求,如果你需要做的事情超出了简单的 GET 调用,这可能会变得很麻烦。 这时,你最好使用 curl。