blog/docs/code/linux/linux-curl.md

686 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Curl命令详解
date: 2020-07-01 15:17:49
tags: [Linux]
categories: [Linux]
author: Anges黎梦
---
### 什么是Curl
cURL是在命令行下工作的文件传输工具。
他的语法是基于URl的语法。
它支持文件上传和下载所以是综合传输工具但按传统习惯称cURL为下载工具。
cURL还包含了用于程序开发的libcurl。
### Curl支持协议
cURL支持的通信协议有
FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP和RTSP。
curl还支持SSL认证、HTTP POST、HTTP PUT、FTP上传,
HTTP form based upload、proxies、HTTP/2、cookies、用户名+密码认证(Basic, Plain, Digest, CRAM-MD5, NTLM,
Negotiate and Kerberos)、file transfer resume、proxy tunneling。
### Curl场景使用
#### HTTP方法
在每一个HTTP请求中都有一个对应的方法常用的方法有GET、POST、HEAD和PUT。
如果在一个curl命令中不指定具体的方法那么默认的就是使用**GET**方法。对于其它的方法可以在curl命令中指定
method|option|
---|:--:|
POST|-d或-F|
HEAD|-I|
PUT|-T|
#### Header
在curl中使用 **-i** 选项可以显示Response的Header信息连同Body数据
```
$ curl -i www.baidu.com
```
结果:
```
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: Keep-Alive
Content-Length: 2381
Content-Type: text/html
Date: Mon, 17 Sep 2018 10:26:42 GMT
Etag: "588604dd-94d"
Last-Modified: Mon, 23 Jan 2017 13:27:57 GMT
Pragma: no-cache
Server: bfe/1.0.8.18
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
\<!DOCTYPE html\>
\<!--STATUS OK--\>\<html\> \<head\>\<meta http-equiv=content-type content=text/html;charset=utf-8\>\<meta
http-equiv=X-UA-Compatible content=IE=Edge\>\<meta content=always name=referrer\>\<link rel=styleshee
t type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css\>\<title\>百度一下,你就
知道\</title\>\</head\> \<body link=#0000cc\> ... \</body\> \</html\>
```
使用 **-I** 选项可以只显示Response的Header信息
```
$ curl -I www.baidu.com
```
#### POST
**POST**是HTTP中向服务端提交数据的一种方法。
在浏览器中,但在表单中填写完数据后,浏览器就会默认将填写的数据使用 **key=value** 串的形式进行转化。
在curl中我们可以使用 **-d** 或 **--data** 选项来指定具体的数据:
```
$ curl -d key1=value1&key2=value2 http://example.com
```
我们也可以使用多个 **-d** 选项来指定多组数据curl会自动把这些数据连接起来因此上面的例子还可以这样
```
$ curl -d key1=value1 -d key2=value2 http://example.com
```
当然,如果数据过多,我们还可以把数据放在一个文件中:
```
$ curl -d @filename http://example.com
```
##### Content-Type
当使用**POST**方法提交数据时,对于提交的数据主要有如下四种形式:
- **application/x-www-form-urlencoded**:默认的形式,即**key1=value1&key2=value2**的形式;
- **multipart/form-data**:使用表单上传文件时使用这个形式;
- **application/json**提交JSON格式的数据
- **text/xml**提交XML格式的数据。
**Content-Type**是一个Header如果不指定的话那么默认就是使用application/x-www-form-urlencoded形式传输数据
当需要使用别的形式进行数据传输的话那么就需要指定这个Header
```
$ curl -d '{I Am A JSON FORM}' -H 'Content-Type: application/json' http://example.com
```
其中,**-H**就是用来指定一个具体的Header的选项值就是**key=value** 的形式。当需要指定其它的Header可以使用**-H**选项。
##### POST一个二进制数据
在curl中我们也可以提交一个文件可以使用**--data-binary**选项来指定一个文件:
```
$ curl --data-binary @filename http://example.com
```
##### 转化成一个GET
使用**-G**或**-get**选项可以把一个POST请求转化成一个GET请求。如果有**-d**选项指定的参数那么curl就会把**-d**后面的数据添加到URL的后面用**?**连接。比如:
```
$ curl -d "key1=value1" -G http://example.com
```
得到的请求URL就是
```
http://example.com/?key1=value1
```
##### URL编码
如果使用的数据没有编码那么可以指定curl来帮助自己进行编码。这时可以使用 **--data-urlencode** 选项来指定。比如:
```
$ curl --data-urlencode "name=Alan Walker" http://example.com
```
##### multipart formposts
如果一个HTTP POST具有如下形式的表单
```
\<form action="submit.cgi" method="post" enctype="multipart/form-data"\>
Name: \<input type="text" name="person"\>\<br\>
File: \<input type="file" name="secret"\>\<br\>
\<input type="submit" value="Submit"\>
\</form\>
```
用户可以在**Name**中填写名字,在**File**中选择一个文件,然后单击**Submit**按钮提交数据。
为了可以在curl中模拟这个请求我们可以使用**-F**或**--form**选项来指定数据:
```
$ curl -F person=annonymous -F secret=@filename http://example.com/submit.cgi
```
在上面的表单中,**action**指定了这个请求发送到哪里;**method**指定这是一个**POST**请求;而**enctype**指定了这是一个**multipart formpost**。
当执行上面的curl命令后curl会产生如下的请求头
```
POST /submit.cgi HTTP/1.1
Host: example.com
User-Agent: curl/7.46.0
Accept: */*
Content-Length: 313
Content-Type: multipart/form-data; boundary=------------------------d74496d66958873e
```
其中**Content-Type**是和**enctype**一致的。
当使用**-F**选项时,默认的**Content-Type**就是**multipart/form-data**,不过,我们也可以使用-H进行指定
```
$ curl -F 'name=Dan' -H 'Content-Type: multipart/magic' https://example.com
```
##### -d vs -F
在前面我们介绍了使用**-d**构造一个基本的POST请求和**-F**构造一个multipart formpost请求。那么这两个选项有啥区别以及什么时候使用呢
这两个选项都是把指定的数据发送到服务器上,区别在于数据传递的格式。大多数时候,接收端来指定希望客户端发送数据的格式,客户端不能随意自己指定格式。
- HTML表单
当使用HTML表单时会使用**\<form\>**标签指定一个表单这会让浏览器使用POST方法。如果标签中含有**enctype=multipart/form-data**
这意味着使用multipart formpost方式在curl中就是使用**-F**选项。一个典型的场景就是表单中含有**\<input type=file\>**标签。
- 不用HTML表单
**POST**方法不一定非要在HTML中在好多的service、APIs中也可以使用**POST**请求。
如果这些service期望使用JSON或者其它类似的格式的数据那么这就是一个普通的POST请求。
在curl中就可以使用**-d**选项。不过要注意**-d**的默认Content-Type是不是期望的格式如果不是的话可以使用**-H**进行更改。
#### HTTP重定向redirect
重定向是HTTP协议中的一个基础部分。在重定向中服务器给客户端的并不是客户端想要的内容
而是一个车具体的指令,告诉客户端如果想获取想要的数据,应该到哪里去请求。
但不是所有的重定向都一样。重定向之后的请求使用什么方法呢?重定向多久呢?
所有的重定向都会返回**Location:**的Header来指定一个新的URL。
##### curlredirect
在curl中默认不会重定向可以使用-L或--location选项来告诉curl重定向
```
$ curl -L http://example.com
```
##### GET还是POST
第一次请求后,服务器会告诉客户端下一次请求需要使用的方法。关于重定向的响应码如下:
Method|Permanent|Temporary|
---|:--:|:--:|
切换到GET|301|302和303|
使用第一次请求的方法|308|307|
我们可以指定curl在重定向时使用什么方法。
如果我们第一次请求使用的不是GET方法重定向后也不希望curl默认使用GET方法那么我们可以使用--post301,--post302和--post303选项来指定。
#### 修改HTTP请求
每一个请求都有一个请求行、一些请求头和可选的请求体这里我们看看在curl中可以具体修改的部分包括请求行和请求头。
##### 请求方法
在请求行中包含这次请求所使用的方法。我们使用下面的简单命令就可以进行一个GET方法
```
$ curl http://example.com/file
```
这会生成如下的请求行:
```
GET /file HTTP/1.1
```
在HTTP方法中我们可以通过具体的选项指定使用什么方法。这里我们也可以使用-X选项来进行指定
```
$ curl -X POST http://example.com
```
##### 修改请求头
在curl中我们可以使用-H或--header选项来指定Header。之前我们就使用-H指定了Content-Type其实Header就是一个key: value对
```
$ curl -H "HeaderName: HeaderValue" http://example.com
```
##### Referer
我们还可以在curl通过--referer选项来指定我们是从哪里跳转过来的
```
$ curl --referer http://fromexample.com http://toexample.com
```
##### User Agent
这个字段是用来表示客户端的设备信息的服务器会根据这个字段针对不同的设备返回不同格式的网页。在curl中可以使用--user-agent选的来指定
```
$ curl --user-agent "[User Agent]" http://example.com
```
#### Cookies
HTTP是一种无状态的协议为了在会话中保存一些状态可以使用Cookies。服务器通过Set-Cookie:来设置Cookie客户端就可以在下一次请求中携带这些数据。
##### 设置Cookie
我们可以使用--cookie选项来设置一个Cookie
```
$ curl --cookie "CookieName=CookieValue" http://example.com
```
##### 从文件中读取Cookies
curl默认不会记住服务器设置的Cookie也不会在下一次请求中携带Cookie。除非用户通过选项自己设置。
我们可以把之前的Cookies保存到一个文件然后在下一次请求中指定curl读取文件中的Cookies
```
$ curl -b cookies.txt http://example.com
```
-b选项指定curl去给定的文件中读取Cookies。
不过要主要这里仅仅是读取Cookies如果这次请求中服务器修改了Cookie那么curl是不会进行保存的除非我们手动指定。
##### 写Cookies到文件
我们可以使用-c选项指定curl保存这次请求中服务器设置的Cookies
```
$ curl -c cookie.jar.txt http://example.com
```
有时我们既需要从文件中读取Cookies也需要保存服务器设置的Cookies。那么就可以同时使用-b和-c选项
```
$ curl -b cookies.txt -c cookie.jar.txt http://example.com
```
### 工具转换
#### Chrome
在Chrome中打开More tools-\>Developer模式
选择Network选项卡然后就可以看到所有的请求选中相应的请求右键就有Copy as cURL选项单击就可以了。
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/chrome-copy.png)
复制出来的结果如下:
```
curl 'https://www.baidu.com/sugrec?prod=pc_his&from=pc_web&json=1&sid=1421_31670_32139_31253_32045_31640&hisdata=%5B%7B%22time%22%3A1576475227%2C%22kw%22%3A%22brew%22%7D%2C%7B%22time%22%3A1576481205%2C%22kw%22%3A%22perfdog%22%2C%22fq%22%3A2%7D%2C%7B%22time%22%3A1576481477%2C%22kw%22%3A%22django%E5%BA%8F%E5%88%97%E5%8C%96%E6%9F%A5%E8%AF%A2%E5%8D%95%E6%9D%A1%E6%95%B0%E6%8D%AE%22%7D%2C%7B%22time%22%3A1576487983%2C%22kw%22%3A%22%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%22%7D%2C%7B%22time%22%3A1576487994%2C%22kw%22%3A%22jq%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%22%7D%2C%7B%22time%22%3A1576488025%2C%22kw%22%3A%22jq%E5%AE%9E%E7%8E%B0%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%22%7D%2C%7B%22time%22%3A1576488314%2C%22kw%22%3A%22require%20%E5%80%92%E5%8C%85%22%7D%2C%7B%22time%22%3A1576488328%2C%22kw%22%3A%22require%20%E5%80%92%E5%8C%85js%22%7D%2C%7B%22time%22%3A1576488745%2C%22kw%22%3A%22%E5%AE%9A%E4%BD%8D%E5%A4%A7%E6%AE%B5html%E5%B9%B6%E6%9B%B4%E6%94%B9%E5%85%B6%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%22%7D%2C%7B%22time%22%3A1576509198%2C%22kw%22%3A%22mac%E4%B8%8A%E5%A5%BD%E7%94%A8%E7%9A%84%E9%9F%B3%E4%B9%90%E6%92%AD%E6%94%BE%E5%99%A8%22%7D%5D&req=2&csor=0' \
-H 'Connection: keep-alive' \
-H 'Accept: application/json, text/javascript, */*; q=0.01' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36' \
-H 'Sec-Fetch-Site: same-origin' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Sec-Fetch-Dest: empty' \
-H 'Referer: https://www.baidu.com/' \
-H 'Accept-Language: zh-CN,zh;q=0.9' \
-H 'Cookie: BIDUPSID=CC7B33A0192F00B390F121986B2F17F4; PSTM=1576163232; BAIDUID=CC7B33A0192F00B33DCFAA82F58706DB:FG=1; BDUSS=xUVGtDSzdwQVlGT1cxcGpSUGtreVg3bGdXNnJEQW83TW16OGF6NzZKdXh3aDllSVFBQUFBJCQAAAAAAAAAAAEAAAB-tN0E6dnA6MPOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALE1-F2xNfhdN2; MCITY=-%3A; BD_UPN=123253; COOKIE_SESSION=8366_0_8_5_3_14_0_1_8_1_0_2_21552_0_1_0_1593346129_0_1593346128%7C9%237395222_271_1591328239%7C9; BD_HOME=1; delPer=0; BD_CK_SAM=1; PSINO=5; H_PS_PSSID=1421_31670_32139_31253_32045_31640; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDRCVFR[feWj1Vr5u3D]=mk3SLVN4HKm; H_PS_645EC=9e81xM8yrPa1O7oMg2rlWLBCpc%2Fir5Ui5T3YIjWLt6FgLOUupOcgrB80vPdGV3EavmJj; WWW_ST=1593599945002; sug=3; sugstore=1; ORIGIN=0; bdime=0' \
--compressed
```
#### Fiddler
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/curl-fildder.png)
右上角 File-\> Export Sessions -\> Selected Sessions
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/curl2.png)
选项第一个默认 **cURL script** -next
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/curl3.png)
文件名自己定义,保存到电脑本地
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/curl4.png)
login.bat 的内容可以打开,复制出来
```shell script
curl -k -i --raw -o 0.dat -X POST "http://49.x.x.x:6000/api/v1/login" -H "User-Agent: Fiddler" -H "Content-Type: application/json" -H "Host: 49.x.x.x:6000"
```
#### Charles
先抓到你想要导出的接口。
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/curl5.png)
如果导出的curl不能使用先查看导出的信息。
```shell script
curl -H 'Host: xxx.com' -H 'Accept: application/json' -H 'User-Agent: kwai-ios' -H 'Accept-Language: zh-Hans-CN;q=1' --compressed 'http://xxx.com'
```
问题出现在结尾网址,请将结尾网址提到最前面就可以了。
```shell script
curl 'http://xxx.com' -H 'Host: xxx.com' -H 'Accept: application/json' -H 'User-Agent: kwai-ios' -H 'Accept-Language: zh-Hans-CN;q=1' --compressed
```
#### Postman
在请求右边点击 **Code**
选择cUrl右边就会展示转换后的内容。
![](https://limeng-blog.oss-cn-hangzhou.aliyuncs.com/code/curl3.png)
### Curl参数详解
#### -A
-A参数指定客户端的用户代理标头即User-Agent。curl 的默认用户代理字符串是curl/[version]。
```
$ curl -A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36' https://google.com
```
上面命令将User-Agent改成 Chrome 浏览器。
```
$ curl -A '' https://google.com
```
上面命令会移除User-Agent标头。
也可以通过-H参数直接指定标头更改User-Agent。
```
$ curl -H 'User-Agent: php/1.0' https://google.com
```
#### -b
-b参数用来向服务器发送 Cookie。
```
$ curl -b 'foo=bar' https://google.com
```
上面命令会生成一个标头Cookie: foo=bar向服务器发送一个名为foo、值为bar的 Cookie。
```
$ curl -b 'foo1=bar;foo2=bar2' https://google.com
```
上面命令发送两个 Cookie。
```
$ curl -b cookies.txt https://www.google.com
```
上面命令读取本地文件cookies.txt里面是服务器设置的 Cookie参见-c参数将其发送到服务器。
#### -c
-c参数将服务器设置的 Cookie 写入一个文件。
```
$ curl -c cookies.txt https://www.google.com
```
上面命令将服务器的 HTTP 回应所设置 Cookie 写入文本文件cookies.txt。
#### -d
-d参数用于发送 POST 请求的数据体。
```
$ curl -d'login=emmapassword=123'-X POST https://google.com/login
# 或者
$ curl -d 'login=emma' -d 'password=123' -X POST https://google.com/login
```
使用-d参数以后HTTP 请求会自动加上标头Content-Type : application/x-www-form-urlencoded。并且会自动将请求转为 POST 方法,因此可以省略-X POST。
-d参数可以读取本地文本文件的数据向服务器发送。
```
$ curl -d '@data.txt' https://google.com/login
```
上面命令读取data.txt文件的内容作为数据体向服务器发送。
#### --data-urlencode
--data-urlencode参数等同于-d发送 POST 请求的数据体,区别在于会自动将发送的数据进行 URL 编码。
```
$ curl --data-urlencode 'comment=hello world' https://google.com/login
```
上面代码中发送的数据hello world之间有一个空格需要进行 URL 编码。
#### -e
-e参数用来设置 HTTP 的标头Referer表示请求的来源。
```
curl -e 'https://google.com?q=example' https://www.example.com
```
上面命令将Referer标头设为https://google.com?q=example。
-H参数可以通过直接添加标头Referer达到同样效果。
```
curl -H 'Referer: https://google.com?q=example' https://www.example.com
```
#### -F
-F参数用来向服务器上传二进制文件。
```
$ curl -F 'file=@photo.png' https://google.com/profile
```
上面命令会给 HTTP 请求加上标头Content-Type: multipart/form-data然后将文件photo.png作为file字段上传。
-F参数可以指定 MIME 类型。
```
$ curl -F 'file=@photo.png;type=image/png' https://google.com/profile
```
上面命令指定 MIME 类型为image/png否则 curl 会把 MIME 类型设为application/octet-stream。
-F参数也可以指定文件名。
```
$ curl -F 'file=@photo.png;filename=me.png' https://google.com/profile
```
上面命令中原始文件名为photo.png但是服务器接收到的文件名为me.png。
#### -G
-G参数用来构造 URL 的查询字符串。
```
$ curl -G -d 'q=kitties' -d 'count=20' https://google.com/search
```
上面命令会发出一个 GET 请求,实际请求的 URL 为https://google.com/search?q=kitties&count=20。如果省略--G会发出一个 POST 请求。
如果数据需要 URL 编码,可以结合--data--urlencode参数。
```
$ curl -G --data-urlencode 'comment=hello world' https://www.example.com
```
#### -H
-H参数添加 HTTP 请求的标头。
```
$ curl -H 'Accept-Language: en-US' https://google.com
```
上面命令添加 HTTP 标头Accept-Language: en-US。
```
$ curl -H 'Accept-Language: en-US' -H 'Secret-Message: xyzzy' https://google.com
```
上面命令添加两个 HTTP 标头。
```
$ curl -d '{"login": "emma", "pass": "123"}' -H 'Content-Type: application/json' https://google.com/login
```
上面命令添加 HTTP 请求的标头是Content-Type: application/json然后用-d参数发送 JSON 数据。
#### -i
-i参数打印出服务器回应的 HTTP 标头。
```
$ curl -i https://www.example.com
```
上面命令收到服务器回应后,先输出服务器回应的标头,然后空一行,再输出网页的源码。
#### -I
-I参数向服务器发出 HEAD 请求,然会将服务器返回的 HTTP 标头打印出来。
```
$ curl -I https://www.example.com
```
上面命令输出服务器对 HEAD 请求的回应。
--head参数等同于-I。
```
$ curl --head https://www.example.com
```
#### -k
-k参数指定跳过 SSL 检测。
```
$ curl -k https://www.example.com
```
上面命令不会检查服务器的 SSL 证书是否正确。
#### -L
-L参数会让 HTTP 请求跟随服务器的重定向。curl 默认不跟随重定向。
```
$ curl -L -d 'tweet=hi' https://api.twitter.com/tweet
```
#### --limit-rate
--limit-rate用来限制 HTTP 请求和回应的带宽,模拟慢网速的环境。
```
$ curl --limit-rate 200k https://google.com
```
上面命令将带宽限制在每秒 200K 字节。
#### -o
-o参数将服务器的回应保存成文件等同于wget命令。
```
$ curl -o example.html https://www.example.com
```
上面命令将www.example.com保存成example.html。
#### -O
-O参数将服务器回应保存成文件并将 URL 的最后部分当作文件名。
```
$ curl -O https://www.example.com/foo/bar.html
```
上面命令将服务器回应保存成文件文件名为bar.html。
#### -s
-s参数将不输出错误和进度信息。
```
$ curl -s https://www.example.com
```
上面命令一旦发生错误,不会显示错误信息。不发生错误的话,会正常显示运行结果。
如果想让 curl 不产生任何输出,可以使用下面的命令。
```
$ curl -s -o /dev/null https://google.com
```
#### -S
-S参数指定只输出错误信息通常与-s一起使用。
```
$ curl -s -o /dev/null https://google.com
```
上面命令没有任何输出,除非发生错误。
#### -u
-u参数用来设置服务器认证的用户名和密码。
```
$ curl -u 'bob:12345' https://google.com/login
```
上面命令设置用户名为bob密码为12345然后将其转为 HTTP 标头Authorization: Basic Ym9iOjEyMzQ1。
curl 能够识别 URL 里面的用户名和密码。
```
$ curl https://bob:12345@google.com/login
```
上面命令能够识别 URL 里面的用户名和密码,将其转为上个例子里面的 HTTP 标头。
```
$ curl -u 'bob' https://google.com/login
```
上面命令只设置了用户名执行后curl 会提示用户输入密码。
#### -v
-v参数输出通信的整个过程用于调试。
```
$ curl -v https://www.example.com
```
--trace参数也可以用于调试还会输出原始的二进制数据。
```
$ curl --trace - https://www.example.com
```
#### -x
-x参数指定 HTTP 请求的代理。
```
$ curl -x socks5://james:cats@myproxy.com:8080 https://www.example.com
```
上面命令指定 HTTP 请求通过myproxy.com:8080的 socks5 代理发出。
如果没有指定代理协议,默认为 HTTP。
```
$ curl -x james:cats@myproxy.com:8080 https://www.example.com
```
上面命令中,请求的代理使用 HTTP 协议。
#### -X
-X参数指定 HTTP 请求的方法。
```
$ curl -X POST https://www.example.com
```
上面命令对https://www.example.com发出 POST 请求。