curl使用指南

作者: 起名难倒英雄汉 | 来源:发表于2018-09-17 18:36 被阅读0次

    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选项,单击就可以了。

    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使用指南

        本文链接:https://www.haomeiwen.com/subject/ounrnftx.html