curl

curl POST JSON 数据

curl -X PUT -H "Content-Type: application/json" -d '@/tmp/demo.json' :9200/demo
ø> cat /tmp/demo.json
{
    "settings": {
        "number_of_shards": 1,
        "number_of_replicas": 1
    }
}

使用 --resolve 选项替换域名

curl -v --resolve www.google.com:8000:127.0.0.1 http://www.google.com:8000/ping

curl -v --resolve www.google.com:443:127.0.0.1 https://www.google.com/ping

curl -v --resolve www.google.com:80:127.0.0.1 http://www.google.com/ping

--fail--fail-with-body

这两个选项都可以让 curl 在接收到 400 及以上的 HTTP 响应码的时候,将退出码设置为 22

--fail-with-body 会输出服务端返回的内容到 stdout 或文件中

--fail 不会有任何输出,当服务端返回的是认证相关的状态码时(401/407), 可能会让使用者误以为出错了

使用场景

在一个 dockerfile 中,我期望下载项目的 go.modgo.sum 文件,然后再执行 go mod download。 这样可以在 clone 代码之前,先下载 go module 文件。

如果项目的代码变了,但是依赖并没有变,因为 docker build 的缓存原理,可以省去下载 go module 的步骤。

...
ARG app_repo
ARG app_commit

RUN [[ ! -d /tmp/app ]] && mkdir /tmp/app && \
    curl -s https://raw.githubusercontent.com/${app_repo}/${app_commit}/go.mod -o /tmp/app/go.mod && \
    curl -s https://raw.githubusercontent.com/${app_repo}/${app_commit}/go.sum -o /tmp/app/go.sum

RUN cd /tmp/app && go mod download
...

当 app_repo 和 app_commit 参数错误,导致对应的 go.mod 文件不存在,curl 会得到 404 的 HTTP 响应码,此时我期望 docker build 出错。

但实际上并不会出错,docker build 会继续执行,直到 go mod download 文件无法识别 go.mod 文件,docker build 才会异常退出。

显示的错误内容如下:

0.467 go: errors parsing go.mod:
0.467 /tmp/app/go.mod:1: unknown directive: 404:

当我给 curl 加上了 --fail 选项之后,程序就会在下载 go.mod 出错时直接退出。显示的错误如下:

ERROR: failed to solve: 
	process "
		/bin/bash -c [[ ! -d /tmp/app ]] && mkdir /tmp/app &&
		curl --fail -s https://raw.githubusercontent.com/${app_repo}/${app_commit}/go.mod -o /tmp/app/go.mod &&
		curl -s https://raw.githubusercontent.com/${app_repo}/${app_commit}/go.sum -o /tmp/app/go.sum
	" did not complete successfully: exit code: 22

最终的 dockerfile 代码及复现命令

FROM golang:1.19
SHELL ["/bin/bash", "-c"]

ARG app_repo
ARG app_commit

RUN go env -w GOPROXY=https://goproxy.cn,direct

RUN [[ ! -d /tmp/app ]] && mkdir /tmp/app && \
    curl --fail -s https://raw.githubusercontent.com/${app_repo}/${app_commit}/go.mod -o /tmp/app/go.mod && \
    curl -s https://raw.githubusercontent.com/${app_repo}/${app_commit}/go.sum -o /tmp/app/go.sum

RUN cd /tmp/app && go mod download
RUN HTTP_PROXY='http://改成你自己的代理' HTTPS_PROXY='http://改成你自己的代理' git clone https://github.com/${app_repo}.git ~/app
RUN cd ~/app && git reset --hard ${app_commit} && go build .
  • 复现命令
# 注意这个 app_commit 是一个不存在的 commit
docker build -t curl_test --build-arg app_repo=bwangelme/rdcdemo --build-arg app_commit=2f24a0658d7feb0205e7d75b7ae218ff6495e8f3 .

使用代理

  • 使用 http 代理
curl -x http://127.0.0.1:1087 https://www.google.com/

# 可以简写, 默认的 proxy 协议是 http

curl -x 127.0.0.1:1087 https://www.google.com/
  • 使用 socks5 代理
curl --socks5-hostname 127.0.0.1:1080 https://www.google.com/

# 可以简写, socks 代理默认端口是 1080

curl --socks5-hostname 127.0.0.1 https://www.google.com/

# 使用 -x 的形式写代理地址, socks5h 等价于 --socks5-hostname
curl -x 'socks5h://localhost:1080' https://www.google.com

注意: socks5 代理必须使用 --socks5-hostname 选项, 不能使用 --socks5 , 要不然 dns 解析不会走代理, 导致请求失败

socks5 和 socks5h 主要区别在于DNS解析的处理方式:

  • socks5: 在这种模式下,DNS解析是在客户端(即你本地的计算机)进行的。这意味着你本地的DNS服务器会解析你请求的域名,然后通过SOCKS5代理将请求发送出去。
  • socks5h: 在这种模式下,DNS解析是在代理服务器上进行的。这意味着代理服务器会解析域名,然后通过代理将请求发往目标服务器。这种方式有助于隐藏你的本地IP地址和DNS查询结果,增加了隐私保护。
  • 覆盖环境变量的代理
# -x '' 指定代理为空, 使得 curl 不走代理, 覆盖了环境变量 http_proxy 设置的代理

$ http_proxy='http://127.0.0.1:1087' curl -x '' cip.cc
IP      : 122.190.50.89
地址    : 中国  湖北  武汉
2023年08月01日 / 11:50