关于CURL命令的一些知识

1. 网络和协议

    在深入讨论如何使用curl完成任务之前,让我们先来看看这些网络是什么以及它是如何工作的,使用简单化和一些小的快捷方式来给出一个简单的概述。
    基本内容在“网络简介”一章中,该章试图从curl的角度简单描述什么是网络,协议部分解释什么是“协议”以及如何工作。

1.1 网络简介

    联网是指在因特网上的两个端点之间进行通信。互联网只是一堆相互连接的机器(实际上是计算机),每一台都使用自己的私有地址(称为IP地址)。每台机器的地址可以是不同类型的,机器甚至可以有临时地址。这些计算机通常被称为主机。
    坐在你前面的电脑、平板电脑或电话通常被称为“客户机”,而你想与之交换数据的机器则被称为“服务器”。客户机和服务器之间的主要区别在于它们在这里扮演的角色。没有什么能阻止角色在后续操作中被反转。

1.1.1 哪台机器

    当您想启动到某台机器(服务器)的传输时,您通常不知道它的IP地址,而是通常知道它的名称。当您使用curl时,将要与之交谈的机器的名称嵌入到您使用的URL中。
    您可以使用类似“http://example.com/index.html”的URL,这意味着您将连接到名为example.com的主机并与之通信。

1.1.2 主机名解析

    一旦我们知道了主机名,我们就需要找出该主机有哪些IP地址,以便我们可以联系它。
    将名称转换为IP地址通常称为“名称解析”。名称被“解析”为一组地址。这通常是由一个“DNS服务器”来完成的,DNS就像一个大的查找表,可以将名字转换成地址,在互联网上的所有名字,真的。您的计算机通常已经知道运行DNS服务器的计算机的地址,因为这是设置网络的一部分。
    因此curl会问DNS服务器:“您好,请给我example.com所有的地址”,服务器会用它们的列表来响应。在拼写错误的情况下,它会回答该名称不存在。

1.1.3 建立联系

    有了curl想要联系的主机的IP地址列表,curl发送一个“connect request”。curl想要建立的连接称为TCP,它的工作方式类似于在两台计算机之间连接一个不可见的字符串。一旦建立,它就可以向两个方向发送数据流。
    当curl获取主机的地址列表时,它实际上会在连接时遍历该地址列表,如果一个地址列表失败,它会尝试连接到下一个地址列表,直到其中一个工作或它们全部失败。

1.1.4 连接到端口号

    当准备使用TCP连接到远程服务器时,客户端需要选择在哪个端口号上执行此操作。端口号专用于特定服务,服务器可以同时监听其他端口号上的其他服务。
    大多数常见的协议都有客户机和服务器使用的默认端口号。例如,当使用“http://example.com/index.html”URL时,该URL指定了一个名为“http”的协议,该协议告诉客户端默认情况下应在服务器上尝试使用TCP端口号80。URL可以选择性地提供另一个自定义端口号,但是如果没有指定特殊的端口号,它将使用协议的默认端口。

1.1.5 TLS

    TCP连接建立后,许多传输都需要双方协商一个更好的安全级别才能继续,这通常是TLS:传输层安全协议。如果使用了这种协议,客户机和服务器将首先进行TLS握手,并且只有在握手成功后才能继续。

1.1.6 传输数据

    当我们称之为TCP的连接“字符串”连接到远程计算机时(我们已经完成了可能的额外TLS握手),两台计算机之间建立了连接,然后可以使用该连接交换数据。通信是使用“协议”完成的,如下一章所述。

1.2 协议

    用于向任意方向请求数据的语言称为协议。协议准确地描述了如何向服务器请求数据,或者告诉服务器有数据要来。
协议通常由IETF定义,IETF掌握RFC文档,这些文档准确描述了每个协议的工作方式:客户机和服务器应该如何工作,发送什么等等。

1.3 curl支持哪些协议?

    curl支持允许在任意一个或两个方向上进行“数据传输”的协议。我们通常使用“URI格式”的协议,或者至少在某种程度上被广泛使用的协议,因为curl主要搭配url(实际上是URI)作为指定传输的关键输入。
    最新的curl(截至本文撰写时)支持以下协议:
DICT,FILE,FTP,FTPS,GOPHER,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,POP3,POP3S,RTMP,RTSP,SCP,SFTP,SMB,SMBS,SMTPS,TELNET,TFTP
    更复杂的是,协议往往存在不同的版本或特点。

2. CURL的使用

    curl最初是一个命令行工具,多年来成千上万的用户从shell提示和脚本中调用它。curl已经将自己确立为那些值得信赖的工具之一,可以帮助您完成工作。

2.1 详细模式

    如果curl命令没有执行或返回您期望的结果,您的第一个直觉反应应该是使用-v/–verbose选项运行该命令以获取更多信息。
    当启用详细模式时,curl会解释和显示更多的行为。它将添加测试信息并在其前面加上“*”。例如,一个简单的HTTP示例(将下载的数据保存在名为“saved”的文件中):

# curl -v http://example.com -o saved
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* About to connect() to example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: example.com
> Accept: */*
> 
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Fri, 15 Nov 2019 03:43:03 GMT
< Etag: "3147526947"
< Expires: Fri, 22 Nov 2019 03:43:03 GMT
< Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
< Server: ECS (sgt/B386)
< Vary: Accept-Encoding
< X-Cache: HIT
< Content-Length: 1256
< 
{ [data not shown]
100  1256  100  1256    0     0   2984      0 --:--:-- --:--:-- --:--:--  2990
* Connection #0 to host example.com left intact

    其中

* Connected to example.com (93.184.216.34) port 80 (#0)

    (#0)是curl给出此连接的内部数字。如果在同一个命令行中尝试多个url,可以看到它使用更多的连接或重用连接,因此连接计数器可能会增加,这取决于curl决定它需要做什么。
    如果我们使用HTTPs://URL而不是HTTP,那么还会有一大堆行解释curl如何使用CA证书来验证服务器的证书,以及服务器证书中的一些细节等等。包括选择了哪些密码以及更多的TLS细节。
    HTTP请求报头的最后一行看起来是空的。它表示头和正文之间的分离,在这个请求中没有要发送的“正文”:

> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: example.com
> Accept: */*
> 

    继续并假设一切都按计划进行,发送的请求将从服务器获得相应的响应,并且HTTP响应将在响应主体之前以一组报头开始:

< HTTP/1.1 200 OK
< Accept-Ranges: bytes
...
< Content-Length: 1256
<

    第一行的“200”可能是其中最重要的一条信息,意思是“一切都很好”。如您所见,接收到的报头的最后一行是空的,这是HTTP协议用来表示头结束的标记。
    头之后是实际的响应体,即数据有效负载。
    您还可以看到一个名为Content-Length的响应报头:在响应中它包含了确切的文件长度(响应中偶尔不存在)。

2.1.1 -‌-trace和-‌-trace ascii(用于抓包)

    有时-v是不够的。特别是,当您想要存储包括实际传输数据的完整流时。
    对于curl使用HTTPS、FTPS或SFTP等协议进行加密文件传输的情况,其他网络监视工具(如Wireshark或tcpdump)将无法为您轻松地完成这项工作。
    为此,curl提供了另外两个选项,您可以使用它们代替-v。
-‌-trace [filename] 将在给定的文件名中保存完整跟踪。

# curl --trace dump http://example.com

    命令运行完,会在当前目录下生成一个名为dump的文件,内容大致如下:

== Info: About to connect() to example.com port 80 (#0)
== Info:   Trying 93.184.216.34...
== Info: Connected to example.com (93.184.216.34) port 80 (#0)
=> Send header, 75 bytes (0x4b)
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 32 39 2e 30 0d 0a 48 6f 73 74 3a 20 65 /7.29.0..Host: e
0030: 78 61 6d 70 6c 65 2e 63 6f 6d 0d 0a 41 63 63 65 xample.com..Acce
0040: 70 74 3a 20 2a 2f 2a 0d 0a 0d 0a                pt: */*....
<= 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, 31 bytes (0x1f)
...

    和其他抓包软件的亚子是一样的。
–trace-ascii [filename] 就是将十六进制转化为ascii码表示。

2.2 持久连接

    在设置到站点的TCP连接时,curl会将旧连接保留一段时间,以便如果下一次传输到同一主机,它可以再次重用同一连接,从而节省大量时间。我们称之为持久连接。CURL将尽可能地保持连接的存在并尽可能重用现有的连接。
    如果要对同一主机或同一基本URL执行N个传输或操作,可以通过尝试在尽可能少的curl命令行中执行这些传输或操作,而不是一次用一个URL重复调用curl,从而获得很大的速度。

2.3 下载

    curl默认把下载的数据输出到标准输出。可以为curl提供一个特定的文件名,以便用 -o [filename] 保存下载,其中filename可以是一个文件名、一个相对路径的文件名或一个完整路径的文件名。

2.3.1 Shell重定向

    从shell或其他命令行提示系统调用curl时,该环境通常为您提供一组输出重定向功能。在大多数Linux和Unix shell,Windows的命令提示框中,可以使用 >filename 将标准输出写入文件。当然,使用这个会使-o或-O的使用变得多余。

curl http://example.com/ > example.html

    UNIX Shell通常允许您使用 2>file 单独重定向标准错误流。标准输出流用于数据,而标准错误流是元数据和错误等,它们不是数据。

curl http://example.com > files.html 2>errors
2.3.2 多次下载

    curl可以在一个命令行中下载许多url。每个下载URL都需要自己的“存储指令”。如果没有“存储指令”,curl默认将数据发送到标准输出。如下示例,如果您请求两个URL,并且只告诉curl在哪里保存第一个URL,那么第二个URL将被发送到标准输出。

curl -o one.html http://example.com/1 http://example.com/2

    这些例子的工作原理都是一样的:

curl -o 1.txt -o 2.txt http://example.com/1 http://example.com/2
curl http://example.com/1 http://example.com/2 -o 1.txt -o 2.txt
curl -o 1.txt http://example.com/1 http://example.com/2 -o 2.txt
curl -o 1.txt http://example.com/1 -o 2.txt http://example.com/2

    不行,得尽快进入正题了,再这样写下去没完了。

3. 如何使用curl进行HTTP

    HTTP一直是curl支持的最重要和最常用的协议。

3.1 HTTP方法

    在每个HTTP请求中,都有一个方法。最常用的是GET、POST、HEAD和PUT。
    但是,通常不会在命令行中指定方法,使用的确切方法取决于您使用的特定选项。GET是默认值,使用-d或-F使其成为POST,-I 生成HEAD,-T 发送PUT。

3.2 HTTP POST

    POST是一种HTTP方法,客户端用来向接收的web应用程序发送数据,它是web上最常见的HTML表单的工作方式。它通常向接收者发送相对少量的数据块。
    当数据被填入表单由浏览器发送时,它将以 name=value 的形式发送URL编码,name=value之间使用与符号(&)分隔。使用 -d发送数据:

curl -d 'name=admin&shoesize=12' http://example.com/

    当在命令行中指定多个-d选项时,curl会将它们连接起来,并在它们之间插入与号,因此上面的示例也可以如下所示:

curl -d name=admin -d shoesize=12 http://example.com/
3.2.1 Content-Type

    使用curl的-d选项会默认包含一个报头,类似于:Content-Type: application/x-www-form-urlencoded,这是典型的POST方式。

> POST / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: example.com
> Accept: */*
> Content-Length: 22
> Content-Type: application/x-www-form-urlencoded
> 

    许多POST数据的接收者不关心或检查Content-Type报头。
如果这个标题对你来说不够好,当然,你应该替换它,并提供正确的标题。例如,如果您将JSON使用POST方式传到服务器,并希望更准确地告诉服务器内容是什么:

# curl -v -d '{json}' -H 'Content-Type: application/json' https://example.com
...
> POST / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: example.com
> Accept: */*
> Content-Type: application/json
> Content-Length: 6
> 
...
3.3 转换成GET方式

    使用-G或-‌-get选项时,将-d,-‌-data,-‌- data-binary或-‌-data-urlencode指定的所有数据在HTTP GET请求中使用,以“?”分隔。
    此选项使在发布和获取表单之间进行切换变得很容易。

3.4 HTTP重定向

    “重定向”是HTTP协议的基本部分。重定向就像它表面听起来那样。它是服务器向客户端发回的指令,而不是返回客户端所需的内容。服务器基本上是说“去这里看看,来替代你要的东西”。

3.4.1 永久和临时

    重定向是要持续还是暂时保持有效?如果您希望一个GET请求使用另一个GET请求将用户永久重定向到资源B,请返回301。这也意味着用户代理(浏览器)将缓存此内容,并从现在起在请求原始URI时使用新URI。
    临时替代方案是302。现在服务器希望客户机向B发送GET请求,但客户机不缓存该请求,而是在下次重定向时继续尝试原始URI。
    请注意,301和302都将使浏览器在下一个请求中执行GET,这意味着,如果方法以POST开始(并且仅在POST开始时),则更改该方法。这种改变HTTP方法以获取301和302响应的做法据说是“出于历史原因”,大多数公共web都会这样做。
    curl根本不记得或缓存任何重定向,所以对它来说,永久重定向和临时重定向真的没有区别。

3.5 修改HTTP请求

    如前所述,每个HTTP传输都从curl发送HTTP请求开始。该请求由一个请求行和许多请求头组成,本章详细介绍了如何修改所有这些请求。

3.5.1 请求方法

    请求的第一行包括方法。执行一个简单的GET请求:

curl http://example.com/file

    初始请求行如下所示

> GET /file HTTP/1.1

    可以使用 -X 或 --request 来改变GET方法,例如:

# curl -v http://example.com/file -X DELETE
* About to connect() to example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 80 (#0)
> DELETE /file HTTP/1.1
...

    当要求curl执行HTTP传输时,它将根据选项选择正确的方法,因此很少使用 -X 显式地请求它。

3.5.2 锚或碎片(Anchors or fragments)

    URL可以包含一个锚,也称为片段,它在URL的末尾用pound符号(#号)和字符串编写。例如

http://example.com/foo.html#here-it-is

    这个片段部分,从pound/hash符号(就是#号)到URL的结尾,都是本地使用的,不会通过网络发送。curl会将数据剥离并丢弃。

3.5.3 自定义请求头

    在HTTP请求中,在初始请求行之后,通常会有多个请求头。这是一组name:value对,以空行结束,空行将头与下面的请求体(有时是空的)分隔开。
    默认情况下,curl会在请求中传递一些头,例如Host:,Accept:,User-Agent: 和其他一些头,这些头取决于用户要求。
    由curl本身设置的所有头都可以被覆盖,如果需要的话可以被替换。
    -H 或 --header 后接自定义头,如果头字段与curl内部头匹配,它将替换内部头。
    改变host头:

curl -H "Host: test.example" http://example.com/

    增加一个 Elevator: floor-9 头:

# curl -v -H "Elevator: floor-9" http://example.com/
* About to connect() to example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: example.com
> Accept: */*
> Elevator: floor-9
> 
...

    如果您只想删除一个内部生成的头,只需将它赋给curl而不赋任何值,在冒号的右侧什么也没有。
    关闭User-Agent: 头:

# curl -v -H "User-Agent:" http://example.com/
* About to connect() to example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> Accept: */*
> 
...

    最后,如果您真的想在冒号的右侧添加一个没有内容的头(这是很少见的事情),那么它以分号结束头字段名:

# curl -v -H "Empty;" http://example.com
* About to connect() to example.com port 80 (#0)
*   Trying 93.184.216.34...
* Connected to example.com (93.184.216.34) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: example.com
> Accept: */*
> Empty:
> 
...
3.6 Cookies

    HTTP cookies是客户端代表服务器存储的键/值对。它们在随后的请求中被发回,以允许客户端在请求之间保持状态。
    Cookie是由服务器使用set Cookie:头设置的,对于每个Cookie,服务器发送一组额外的属性,这些属性需要与客户端的Cookie相匹配,比如域名和路径,也许cookie的生存时间最重要。
    cookie的到期时间要么设置为将来的固定时间(或生存数秒),要么根本没有到期。一个没有过期时间的cookie称为“会话cookie”,它应该在“会话”期间存在,但不会持续更长时间。此方面的会话通常被认为是浏览器查看站点的生命周期。关闭浏览器时,结束会话。

3.6.1 Cookie引擎

    curl默认关闭Cookie。您需要打开“cookie引擎”,让curl跟踪它接收到的cookie,然后在有匹配cookie的请求时发送它们。通过要求curl读取或写入cookie来启用cookie引擎。如果你告诉CURL从一个不存在的文件读取cookies,你只会打开引擎,然后开启一个空的cookie内部存储:

curl -b non-existing http://example.com

    打开cookie引擎,获取一个资源然后退出将是毫无意义的,因为curl将没有机会实际发送它接收到的任何cookie。假设本例中的站点将设置cookies,然后执行重定向,我们将执行以下操作:

curl -L -b non-existing http://example.com
3.6.2 向文件写入cookies

    Cookie被存储的地方有时被称为“cookie jar”。当你在curl中开启cookie引擎并接收cookie时,在curl退出之前,可以将cookie写入cookie jar。重要的是,curl仅在退出时更新输出到Cookie jar,而不是在其正在运行时输出cookie。
    可以使用 -c 指定输出:

# curl -c cookie-jar.txt http://www.baidu.com
...
# cat cookie-jar.txt 
# Netscape HTTP Cookie File
# http://curl.haxx.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

.baidu.com      TRUE    /       FALSE   1574008911      BDORZ   27315

    当curl将cookies写入这个文件时,它将保存所有已知的cookies,包括那些会话cookies(没有给定的生存期)。curl本身没有会话的概念,它不知道会话何时结束,因此除非您告诉它,否则它不会刷新会话cookie。

3.6.3 从文件读取cookies

    curl用于cookies的文件格式称为Netscape cookie格式,因为它曾经是浏览器使用的文件格式,然后您可以很容易地告诉curl使用浏览器的cookies。
    告诉curl从哪个文件读取初始cookies:

# curl -v -L -b cookie-jar.txt http://www.baidu.com
* About to connect() to www.baidu.com port 80 (#0)
*   Trying 61.135.169.125...
* Connected to www.baidu.com (61.135.169.125) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.baidu.com
> Accept: */*
> Cookie: BDORZ=27315
> 
...

    记住,这只读取文件。如果服务器将在其响应中更新Cookie,则CURL将更新其内存中的cookie,但最终在退出时将它们全部丢弃,并且相同的输入文件的后续调用将再次使用原始Cookie内容。

参考文档

https://ec.haxx.se/
https://hit-alibaba.github.io/interview/basic/network/HTTP.html
https://curl.haxx.se/docs/manual.html
https://www.runoob.com/http/http-tutorial.html
https://curl.haxx.se/docs/manpage.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值