# HTTP协议利器curl

`curl`是一个极其强大的[命令行传输数据的工具和库](https://curl.haxx.se/)，其作用远超过常用的文件加载功能，可以用于各种网络应用协议交互核测试。

## 从文本获取数据内容

如果要通过curl将文本文件内容发送给网站( `post` )，使用`@`符号：

> `-d`表示数据，也可以是 `--data` 。注意，文件名前面一定要加上 `@` 符号。

```bash
curl -k https://<SERVER_IP>/API/xyz -H 'Content-Type: application/json' -d @/var/log/example.log
```

> `-k` 表示`--insecure`，不校验服务器SSL安全性 ，请参考 [How to ignore invalid and self signed ssl connection errors with curl](https://www.cyberciti.biz/faq/how-to-curl-ignore-ssl-certificate-warnings-command-option/) 。特别适合很多内网部署服务，自己签发的非正式证书。

如果是使用curl上传文件，则使用:

```bash
curl --from "fileupload=@filename.txt" http://hostname/resource
```

* 使用RESTful HTTP post:

```bash
curl -X POST -d @filename http://hostname/resource
```

* 提交json数据案例:

```bash
curl -XPOST --data '{"data": 123}' api.example.com/data
```

```bash
curl -XPOST --data @data.json api.example.com/data
```

* 登录网站(auth)：将登录信息记录到headers，后续curl都使用headers

```bash
curl -d "username=admin&password=admin&submit=Login" --dump-header headers http://localhost/Login
curl -L -b headers http://localhost/
```

## 通过curl检查https证书

```bash
curl -v https://www.baidu.com
```

如果服务器是自签名证书，则加上 `-k` 参数。如果想要禁止证书警告，例如你的自签名证书服务器，你需要下载文件，忽略证书告警，在使用参数 `-I` :

```bash
curl -k -O https://202.54.1.2/file.tar.gz
```

另外，如果你仅仅想截取证书信息，则参考

## 提交字段内容null

提交json数据，字段也可以是`null`（例如暂时不知道的字段）:

```bash
curl -k -u user_name:user_password -H "Accept: version=2,application/json" -H "Content-Type: application/json" -X POST -d '{"name": "tom", "phone": null, "address": "x road, y room", "crash_time": "2018-07-26 06:48:02"}' http://myapp.com/api/contact/
```

## 指定CA信任通过curl访问

可以指定自签名证书

```bash
curl --cacert /pth/to/my/ca.pem https://url
curl --header 'Host: www.cyberciti.biz' --cacert /pth/to/my/ca.pem https://207.5.1.10/nixcraft.tar.gz
```

## 脚本方式截取https证书信息

参考 [how to use curl to verify if a site's certificate has been revoked?](https://superuser.com/questions/742393/how-to-use-curl-to-verify-if-a-sites-certificate-has-been-revoked)

使用以下命令获取服务器证书信息（例如检查服务器证书到期时间）:

```bash
curl --insecure -v https://www.baidu.com 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
```

输出可以看到：

```
* Server certificate:
*  subject: C=CN; ST=beijing; L=beijing; OU=service operation department; O=Beijing Baidu Netcom Science Technology Co., Ltd; CN=baidu.com
*  start date: May  9 01:22:02 2019 GMT
*  expire date: Jun 25 05:31:02 2020 GMT
*  issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign Organization Validation CA - SHA256 - G2
*  SSL certificate verify ok.
* Connection #0 to host www.baidu.com left intact
* Closing connection 0
```

## 使用代理服务器

在内网或者生产环境，往往会使用代理服务器来实现集中的internet访问以及缓存加速。curl命令也支持代理功能，只需要设置shell环境变量就可以：

```bash
export http_proxy=http://your.proxy.server:port/
export https_proxy=https://your.proxy.server:port/
```

## 通过钉钉机器人发信息

钉钉支持通过群机器人发送通知信息，但是我没有找到如何用命令参数传递方式发送通知，所以采用的是将文本格式化成json格式存储到文件中，然后通过curl将该文件内容传送给钉钉机器人的URL实现通知。功能是可以正常实现的：

```bash
function ding_alert() {
    robot_url='https://oapi.dingtalk.com/robot/send?access_token=XXXXXXXXXXXXXX'

    ding_data='{"msgtype":"text", "text": {"content": "'
    ding_data=${ding_data}"认证关键字 \n"
    echo $ding_data > ding_data
    cat ding_data_content >> ding_data
    echo '"}}' >> ding_data


    curl $robot_url -H 'Content-Type: application/json' -d @ding_data
}
```

> 文件 `ding_data_content` 是我需要发送给钉钉机器人的消息内容(脚本的其他逻辑会生成这个需要返送消息内容)
>
> 通过组合json格式，将 `ding_data_content` 转成钉钉的 `ding_data`
>
> 这里在文本内容中加入了 `认证关键字` 是为了满足钉钉通知的安全认证，钉钉支持 token和关键字过滤 的安全认证。这里是最简单的方式。
>
> 最后将 `ding_data` 文件发送给钉钉机器人的url

## curl: (1) Protocol "http not supported or disabled in libcurl

需要使用curl来get数据，不过 url 参数是通过访问一个REST接口获得的文件下载链接。这里遇到一个问题，返回的数据是一个json数据，我通过 `jq` 工具可以解析json数据获得URL

```bash
myurl=`curl -q --location --request GET 'http://api.example.com/generatePresignedUrl.json?key=filename' \
--header 'x-apiauth-token: XXXXXX' | jq '.target'`

echo ${myurl}
```

通过 `| jq '.target'` 过滤可以获得文本字符串是带有双引号的 `"url内容"`

```
"http://download.example.com/filename?Expires=123456&Id=XXXXX&Signature=YYYYY"
```

这是就发现，这届使用 `curl ${myurl}` 会出现报错：

```bash
curl: (1) Protocol "http not supported or disabled in libcurl
```

这是因为传递变量的双引号作为字符串一部分被发送给curl处理，导致出错。也就是说，需要过滤掉字符串的前后双引号字符(增加 `| sed 's/\"//g'` ):

```bash
myurl=`curl -q --location --request GET 'http://api.example.com/generatePresignedUrl.json?key=filename' \
--header 'x-apiauth-token: XXXXXX' | jq '.target' | sed 's/\"//g'`

curl ${myurl}
```

## 安静模式

直接使用 `curl` 命令get，会显示一个进度过程输出。不过对于脚本而言不是很好，所以我们需要使用 `-s` 或者 `--silent` 参数，以静默方式下载。如果不希望任何输出，则重定向到null设备

```
curl -s 'http://example.com' > /dev/null

curl --silent --output /dev/null http://example.com
```

## 参考

* [How to POST file contents using cURL?](https://superuser.com/questions/1054742/how-to-post-file-contents-using-curl)
* [How to send a header using a HTTP request through a curl call?](https://stackoverflow.com/questions/356705/how-to-send-a-header-using-a-http-request-through-a-curl-call)
* [Hide curl output](https://unix.stackexchange.com/questions/196549/hide-curl-output)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/develop/shell/utilities/curl.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
