Synopsis

Syntax

curl [options] [URL...]

Description

curl is a tool to transfer data from or to a server, using one of the supported protocols (HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, DICT, TELNET, LDAP or FILE). The command is designed to work without user interaction. curl offers a busload of useful tricks like proxy support, user authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer resume and more. As you will see below, the number of features will make your head spin!

curl is powered by libcurl for all transfer-related features. See libcurl(3) for details.

curl 使用指南

curl是一个命令行工具,通过指定的URL来上传或下载数据,并将数据展示出来。curl中的c表示client,而URL,就是URL。这里我们介绍一下curl的使用。

1. 命令行基础

1.1 命令行选项

1. 短形式

在curl中可以使用短形式的命令行选项,比如通知curl打开verbose模式,可以使用-v选项:

$ curl -v www.baidu.com

这里,-v就是短形式的选项,我们使用一个中划线(-)并紧跟着一个字母来指定一个短形式的选项。

在这个例子中,-v就像一个开关一样,指定某个变量是false还是true。我们可以在一个中划线后面跟多个单字母的选项:

$ curl -vL www.baidu.com

在curl中,命令行解析器总是解析整个命令行,因此,选项可以放在整个命令行的任何位置:

$ curl www.baidu.com -vL

这个和上面的命令具有同样的效果。当然,虽然是任何位置,但不能放在curl前面啊:

$ -vL curl www.baidu.com    // No command '-vL' found

2. 长形式

单个字母的选项敲起来和用起来都很方便,但是字母的个数有限而需要控制的东西又太多,这个时候就可以使用选项的长形式。同样,为了使得命令便于阅读,绝大多数短形式都有一个对应的长形式。

和短形式不同的是,长形式的选项使用两个中划线(–)指定,然后紧跟着具体的选项。还有就是,在使用长形式的时候,后面只能跟一个选项。对于-v,对应的长形式如下:

$ curl --verbose www.baidu.com

同样,长形式的选项也可以出现在命令的任何地方:

$ curl www.baidu.com --verbose

对于-vL来说,对应的长形式可以是:

$ curl --verbose --location www.baidu.com

或者:

$ curl --location www.baidu.com --verbose

3. 选项的参数

在上面的命令中选项-v(或--verbose)以及-L(或--location)都是bool类型的标志位,来告诉curl打开或关闭某些特征。curl还有一种类型的选项,就是需要传递一些参数。比如,如果想在一个HTTP POST中向服务器传递一个字符串:

$ curl -d arbitrary http://example.com

同样,也可以使用相应的长形式:

$ curl --data arbitrary http://example.com

4. 参数有空格?

在上面的例子中,我们的参数arbitrary是一个连续的字符串,但是当我们需要传递一个有空格的参数怎么办?比如Are you OK?,这时我们需要使用引号把参数括起来:

$ curl -A "Are you OK?" http://example.com

如果不加引号的话:

$ curl -A Are you OK? http://example.com

那么curl只会把Are当做用户的参数,剩下的字符,youOK?会被curl当做额外的URL处理,因为这里并没有用-指定这是一个选项。

但是如果参数本身有引号的时候怎么办?这在使用JSON传递参数的时候尤其常见,我们可以使用单引号把参数括起来(不过在Windows中不管用):

$ curl -d '{"name":"fool"}' http://example.com

当数据很多时,我们可以指定一个文件,来传递给curl:

$ curl -d @params.json http://example.com

5. Say No

对于像-t-L之类的标志选项,我们可以在长形式的前面加上no-前缀来指定关闭相应的特征,比如关闭verbose模式:

$ curl --no-verbose http://example.com

1.2 URL

curl支持在一个命令行中处理多个URL,中间用空格间隔即可。curl会对传进来的URL做简单的验证,而不会去验证URL是否真正有效,因此,这里需要使用者提供有效的URL。

前面说过,curl首先解析整个命令行,将得到选项应用于所有的URL上。如果想对每一个URL使用不同的选项,那么可以使用--next来指定。比如:

$ curl --location http://example.com/1 
    --next --data sendthis http://example.com/2 
    --next head http://example.com/3

1. 配置文件

如果选项过多,导致命令很难输入,或者超过了系统命令最大长度的限制,我们可以使用配置文件(config file)来指定curl的选项。

通过使用-K--config选项来告诉curl从指定的文件中读取选项,比如:

$ curl -K curl.options http://example.com

在文件curl.options中,列出所有需要的选项:

# ask curl to follow redirects
--location
# ask curl to do a HEAD request
--head

和在命令行中一样,在配置文件中也可以使用长形式或短形式,甚至在配置文件中对于长形式可以省略那两个中划线(–):

# ask curl to follow redirects
location
# ask curl to do a HEAD request
head

对于使用参数的选项,同样可以使用配置文件:

# ask curl to change the User-Agent in HTTP header
user-agent "something-is-an-agent"

既然叫做配置文件,那么上面的选项也可以写作:

# ask curl to change the User-Agent in HTTP header
user-agent = "something-is-an-agent"

甚至可以省略没有空格的参数的引号:

# ask curl to change the User-Agent in HTTP header
user-agent = something-is-an-agent

当然,如果参数中有空格的话就不能省略引号了。

2. 开始使用curl

在前面我们简单地介绍了什么是curl以及一些基础的命令行知识。我们通过命令行的方式将需要处理的URL交给curl去处理。

在这里,我们开始着手使用curl,了解curl能做什么以及如何去做。

2.1 Verbose模式

如果curl得到的结果不是期望的结果,我们可以使用-v--verbose进入Verbose模式获取更多的信息。

1. 查看通信过程

在Verbose模式中,curl会得到更多的对话式信息,帮助我们了解发生了什么。curl会在每一个信息前面加上*进行标识。在下面的例子中,我们将百度的首页保存下来(使用-o选项并指定参数baidu):

$ curl -v www.baidu.com -o baidu

我们可以得到如下的信息:

* About to connect() to www.baidu.com port 80 (#0)
*   Trying 14.215.177.39... connected
* Connected to www.baidu.com (14.215.177.39) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: www.baidu.com
> Accept: */*
>
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0< 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: Fri, 14 Sep 2018 09:55:18 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=/
<
{ [data not shown]
103  2381  103  2381    0     0   113k      0 --:--:-- --:--:-- --:--:--  232k* Connection #0 to host www.baidu.com left intact

* Closing connection #0

下面的信息是建立一个链接:

* About to connect() to www.baidu.com port 80 (#0)
*   Trying 14.215.177.39... connected
* Connected to www.baidu.com (14.215.177.39) port 80 (#0)

然后就是本次的HTTP请求:

> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: www.baidu.com
> Accept: */*
>

接下来是数据的传输过程。然后就是响应:

< 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: Fri, 14 Sep 2018 09:55:18 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=/
<

连箭头都不一样了。

2. 更详细的信息

如果觉得使用-v的信息还不够的话,还可以使用--trace [filename]选项来讲完整的流保存到filename中。比如:

$ curl --trace dump www.baidu.com

之后,就可以发现一个新的文件dump,里面保存着刚才那个会话的所有信息:

== Info: About to connect() to www.baidu.com port 80 (#0)
== Info:   Trying 14.215.177.39... == Info: connected
== Info: Connected to www.baidu.com (14.215.177.39) port 80 (#0)
=> Send header, 166 bytes (0xa6)
0000: 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
0010: 55 73 65 72 2d 41 67 65 6e 74 3a 20 63 75 72 6c User-Agent: curl
0020: 2f 37 2e 31 39 2e 37 20 28 78 38 36 5f 36 34 2d /7.19.7 (x86_64-
0030: 72 65 64 68 61 74 2d 6c 69 6e 75 78 2d 67 6e 75 redhat-linux-gnu
0040: 29 20 6c 69 62 63 75 72 6c 2f 37 2e 31 39 2e 37 ) libcurl/7.19.7
0050: 20 4e 53 53 2f 33 2e 32 37 2e 31 20 7a 6c 69 62  NSS/3.27.1 zlib
0060: 2f 31 2e 32 2e 33 20 6c 69 62 69 64 6e 2f 31 2e /1.2.3 libidn/1.
0070: 31 38 20 6c 69 62 73 73 68 32 2f 31 2e 34 2e 32 18 libssh2/1.4.2
0080: 0d 0a 48 6f 73 74 3a 20 77 77 77 2e 62 61 69 64 ..Host: www.baid
0090: 75 2e 63 6f 6d 0d 0a 41 63 63 65 70 74 3a 20 2a u.com..Accept: *
00a0: 2f 2a 0d 0a 0d 0a                               /*....
<= Recv header, 17 bytes (0x11)
0000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
0010: 0a                                              .
<= Recv header, 22 bytes (0x16)
0000: 41 63 63 65 70 74 2d 52 61 6e 67 65 73 3a 20 62 Accept-Ranges: b
0010: 79 74 65 73 0d 0a                               ytes..

文件的前21行如上所示。每一个发送和接收的数据以十六进制的形式保存起来了,方便以后的分析。

如果觉得十六进制没啥帮助的话,可以使用--trace-ascii [filename]选项:

$ curl --trace-ascii dump www.baidu.com

结果如下:

== Info: About to connect() to www.baidu.com port 80 (#0)
== Info:   Trying 14.215.177.38... == Info: connected
== Info: Connected to www.baidu.com (14.215.177.38) port 80 (#0)
=> Send header, 166 bytes (0xa6)
0000: GET / HTTP/1.1
0010: User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7
0050:  NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
0082: Host: www.baidu.com
0097: Accept: */*
00a4:
<= Recv header, 17 bytes (0x11)
0000: HTTP/1.1 200 OK
<= Recv header, 22 bytes (0x16)
0000: Accept-Ranges: bytes
<= Recv header, 76 bytes (0x4c)
0000: Cache-Control: private, no-cache, no-store, proxy-revalidate, no
0040: -transform
<= Recv header, 24 bytes (0x18)
0000: Connection: Keep-Alive
<= Recv header, 22 bytes (0x16)
0000: Content-Length: 2381

上面就是前21行的输出。

3. Silence

verbose模式的对立模式,就是silence,可以使用-s--silence选项来告诉curl不输出任何程序的信息或者错误信息,但也会输出响应的结果。

如果需要在有错误的时候输出错误信息,可以使用-S--show-error来指定。

2.2 浏览器到curl

别人使用浏览器发起了一个请求之后,如果自己想用curl再来一次同样的请求,这里日常的工作中是比较常见的一个操作。在curl中,有没有什么比较简便快捷的方式来获得curl命令呢?

Chrome浏览器和Firefox浏览器都实现了复制成curl的工具,可以将浏览器的请求快速复制成curl命令,非常方便快捷。

1. Chrome

在Chrome中,打开More tools->Developer模式,选择Network选项卡,然后就可以看到所有的请求,选中相应的请求,右键就有Copy as cURL选项,单击就可以了。

image

2. Firefox

在Firefox中,打开Web Developer->Network工具,然后右键想要复制的链接,就有一个Copy as cURL的选项,单击就可以了。

3. HTTP与curl

与curl一起使用的协议,最多的还是HTTP,这里就将介绍如何有效地使用curl来发送HTTP请求。

3.1 HTTP方法

在每一个HTTP请求中,都有一个对应的方法,常用的方法有:GETPOSTHEADPUT

如果在一个curl命令中不指定具体的方法,那么默认的就是使用GET方法。对于其它的方法,可以在curl命令中指定:

method option
POST -d-F
HEAD -I
PUT -T

3.2 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

3.3 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

1. 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选项。

2. POST一个二进制数据

在curl中,我们也可以提交一个文件,可以使用--data-binary选项来指定一个文件:

$ curl --data-binary @filename http://example.com

3. 转化成一个GET

使用-G-get选项,可以把一个POST请求转化成一个GET请求。如果有-d选项指定的参数,那么curl就会把-d后面的数据添加到URL的后面,用?连接。比如:

$ curl -d "key1=value1" -G http://example.com

得到的请求URL就是:

http://example.com/?key1=value1

4. URL编码

如果使用的数据没有编码,那么可以指定curl来帮助自己进行编码。这时可以使用--data-urlencode选项来指定。比如:

$ curl --data-urlencode "name=Alan Walker" http://example.com

5. 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

6. -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进行更改。

3.4 HTTP重定向(redirect)

重定向是HTTP协议中的一个基础部分。在重定向中,服务器给客户端的并不是客户端想要的内容,而是一个车具体的指令,告诉客户端如果想获取想要的数据,应该到哪里去请求。

但不是所有的重定向都一样。重定向之后的请求使用什么方法呢?重定向多久呢?

所有的重定向都会返回Location:的Header,来指定一个新的URL。

1. curl:redirect

在curl中,默认不会重定向,可以使用-L--location选项来告诉curl重定向:

$ curl -L http://example.com

2. GET还是POST

第一次请求后,服务器会告诉客户端下一次请求需要使用的方法。关于重定向的响应码如下:

Method Permanent Temporary
切换到GET 301 302和303
使用第一次请求的方法 308 307

我们可以指定curl在重定向时使用什么方法。如果我们第一次请求使用的不是GET方法,重定向后也不希望curl默认使用GET方法,那么我们可以使用--post301,--post302--post303选项来指定。

3.5 修改HTTP请求

每一个请求都有一个请求行、一些请求头和可选的请求体,这里我们看看在curl中可以具体修改的部分,包括请求行和请求头。

1. 请求方法

在请求行中包含这次请求所使用的方法。我们使用下面的简单命令就可以进行一个GET方法:

$ curl http://example.com/file

这会生成如下的请求行:

GET /file HTTP/1.1

HTTP方法中我们可以通过具体的选项指定使用什么方法。这里我们也可以使用-X选项来进行指定:

$ curl -X POST http://example.com

2. 修改请求头

在curl中,我们可以使用-H--header选项来指定Header。之前我们就使用-H指定了Content-Type,其实Header就是一个key: value对:

$ curl -H "HeaderName: HeaderValue" http://example.com

3. Referer

我们还可以在curl通过--referer选项来指定我们是从哪里跳转过来的:

$ curl --referer http://fromexample.com http://toexample.com

4. User Agent

这个字段是用来表示客户端的设备信息的,服务器会根据这个字段,针对不同的设备,返回不同格式的网页。在curl中,可以使用--user-agent选的来指定:

$ curl --user-agent "[User Agent]" http://example.com

3.6 Cookies

HTTP是一种无状态的协议,为了在会话中保存一些状态,可以使用Cookies。服务器通过Set-Cookie:来设置Cookie,客户端就可以在下一次请求中携带这些数据。

1. 设置Cookie

我们可以使用--cookie选项来设置一个Cookie:

$ curl --cookie "CookieName=CookieValue" http://example.com

2. 从文件中读取Cookies

curl默认不会记住服务器设置的Cookie,也不会在下一次请求中携带Cookie。除非用户通过选项自己设置。

我们可以把之前的Cookies保存到一个文件,然后在下一次请求中指定curl读取文件中的Cookies:

$ curl -b cookies.txt http://example.com

-b选项指定curl去给定的文件中读取Cookies。

不过要主要,这里仅仅是读取Cookies,如果这次请求中服务器修改了Cookie,那么curl是不会进行保存的,除非我们手动指定。

3. 写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


参考文献 curl使用实例 Curl使用指南 简书 https://linux.die.net/man/1/curl gihub.com/curl Curl