curl命令可以帮助我们在linux服务内部通讯,排查接口是否能够正确调用,外网的接口是否有防火墙限制,内网的请求可以快速帮我们获取接口参数返回,并且调试程序代码,在局域网,或者内网的时候只能在内网调试,这个时候curl命令足以支持我们完成所有调试和测试。
使用 Curl 编写 HTTP 请求脚本的艺术
背景
本文档假定您熟悉 HTML 和一般网络。
越来越多的应用程序迁移到 Web 使得“HTTP 脚本”的请求和需求更加频繁。能够自动从网络中提取信息、伪造用户、向网络服务器发布或上传数据都是当今重要的任务。
Curl 是一个用于执行各种 URL 操作和传输的命令行工具,但本文档将重点介绍如何在执行 HTTP 请求时使用它以获取乐趣和利润。我将假设您知道如何调用curl --help
或curl --manual
获取有关它的基本信息。
Curl 并不是为你做所有事情。它发出请求,获取数据,发送数据并检索信息。您可能需要使用某种脚本语言或重复的手动调用将所有内容粘合在一起。
HTTP 协议
HTTP 是用于从 Web 服务器获取数据的协议。它是一个建立在 TCP/IP 之上的简单协议。该协议还允许使用几种不同的方法将信息从客户端发送到服务器,如下所示。
HTTP 是由客户端发送到服务器以请求特定操作的纯 ASCII 文本行,然后服务器在实际请求的内容发送到客户端之前回复几行文本。
客户端 curl 发送一个 HTTP 请求。请求包含一个方法(如 GET、POST、HEAD 等)、许多请求标头,有时还包含一个请求正文。HTTP 服务器以状态行(指示事情是否顺利)、响应标头以及最常见的响应正文进行响应。“body”部分是您请求的纯数据,例如实际的 HTML 或图像等。
见协议
使用 curl 的选项--verbose(-v
作为一个简短的选项)将显示 curl 发送到服务器的命令类型,以及一些其他信息文本。
--verbose
是调试甚至理解 curl<-> 服务器交互时最有用的选项。
有时甚至--verbose
是不够的。然后提供更多细节,因为它们显示了--tracecurl发送和接收的所有内容。像这样使用它:--trace-ascii
curl --trace-ascii debugdump.txt http://www.example.com/
看时间
很多时候,您可能想知道到底是什么时间,或者您只想知道传输中两点之间的毫秒数。对于这些情况以及其他类似情况,--trace-time您需要选择该选项。它会将时间添加到每个跟踪输出行:
curl --trace-ascii d.txt --trace-time http://example.com/
查看响应
默认情况下 curl 将响应发送到标准输出。您需要将其重定向到某个地方以避免这种情况,通常是使用 -o
or完成的-O
。
网址
规格
统一资源定位符格式是您指定 Internet 上特定资源地址的方式。你知道这些,你已经看过像https://curl.se或https://yourbank.com这样的 URL一百万次。RFC 3986 是规范规范。是的,正式名称不是 URL,而是 URI。
主持人
主机名通常使用 DNS 或 /etc/hosts 文件解析为 IP 地址,这就是 curl 将与之通信的内容。或者,您可以直接在 URL 中指定 IP 地址而不是名称。
对于开发和其他尝试情况,您可以使用 curl 的--resolve选项为主机名指向不同的 IP 地址,而不是其他情况下使用的 IP 地址:
curl --resolve www.example.org:80:127.0.0.1 http://www.example.org/
端口号
curl 支持的每个协议都在默认端口号上运行,无论是通过 TCP 还是在某些情况下是 UDP。通常您不必考虑这一点,但有时您会在其他端口或类似端口上运行测试服务器。然后,您可以在 URL 中使用冒号和紧跟主机名的数字指定端口号。就像对端口 1234 执行 HTTP 时一样:
curl http://www.example.org:1234/
您在 URL 中指定的端口号是服务器用来提供其服务的端口号。有时您可能会使用代理,然后您可能需要将代理的端口号与 curl 连接到服务器所需的端口号分开。就像在端口 4321 上使用 HTTP 代理一样:
curl --proxy http://proxy.example.org:4321 http://remote.example.org/
用户名和密码
某些服务设置为需要 HTTP 身份验证,然后您需要提供名称和密码,然后根据使用的确切身份验证协议以各种方式将其传输到远程站点。
您可以选择在 URL 中插入用户名和密码,也可以单独提供:
curl http://user:password@example.org/
或者
curl -u user:password http://example.org/
您需要注意的是,这种 HTTP 身份验证并不是当今面向用户的网站通常所做的和要求的。他们倾向于使用表格和cookies。
路径部分
路径部分只是被发送到服务器以请求它发回相关的响应。路径是在主机名和可能的端口号后面的斜杠右侧的内容。
获取页面
得到
使用 HTTP 进行的最简单和最常见的请求/操作是获取 URL。URL 本身可以引用网页、图像或文件。客户端向服务器发出 GET 请求并接收它请求的文档。如果您发出命令行
curl https://curl.se
您会在终端窗口中返回一个网页。该 URL 包含的整个 HTML 文档。
所有 HTTP 回复都包含一组通常隐藏的响应头,使用 curl 的--include( -i
) 选项来显示它们以及文档的其余部分。
头
--head您可以使用( ) 选项仅向远程服务器询问标头,-I
这将使 curl 发出 HEAD 请求。在某些特殊情况下,服务器拒绝 HEAD 方法,而另一些仍然有效,这是一种特殊的烦恼。
HEAD 方法的定义和制作使得服务器返回的标题与它对 GET 所做的完全一样,但没有正文。这意味着您可能会Content-Length:
在响应标头中看到 a,但在 HEAD 响应中不能有实际的正文。
单个命令行中的多个 URL
单个 curl 命令行可能涉及一个或多个 URL。最常见的情况可能是只使用一个,但您可以指定任意数量的 URL。是的,任何。无限。然后,您将收到针对所有给定 URL 的重复请求。
例如,发送两个 GET:
curl http://url1.example.com http://url2.example.com
如果您使用--dataPOST 到 URL,则使用多个 URL 意味着您将相同的 POST 发送到所有给定的 URL。
例如,发送两个 POST:
curl --data name=curl http://url1.example.com http://url2.example.com
单个命令行中的多个 HTTP 方法
有时您需要在一个命令行中对多个 URL 进行操作,并对每个 URL 执行不同的 HTTP 方法。为此,您将享受该--next选项。它基本上是一个分隔符,将一堆选项与下一个选项分开。之前的所有 URL--next
都将获得相同的方法,并将所有 POST 数据合并为一个。
当 curl--next
在命令行上到达时,它将重置方法和 POST 数据并允许新的设置。
也许最好用几个例子来说明这一点。要先发送一个 HEAD,然后再发送一个 GET:
curl -I http://example.com --next http://example.com
要先发送 POST,然后再发送 GET:
curl -d score=10 http://example.com/post.cgi --next http://example.com/results.html
HTML 表单
表格解释
表单是网站呈现 HTML 页面的一般方式,其中包含供用户输入数据的字段,然后按某种“确定”或“提交”按钮将该数据发送到服务器。然后服务器通常使用发布的数据来决定如何行动。就像使用输入的词在数据库中搜索,或在错误跟踪系统中添加信息,在地图上显示输入的地址或使用信息作为登录提示验证用户是否可以查看它的内容查看。
当然,服务器端必须有某种程序来接收您发送的数据。你不能凭空发明一些东西。
得到
GET-form 使用 GET 方法,如 HTML 中指定的那样:
<span style="color:#000000"><span style="background-color:#ffffff"><code><form method="GET" action="junk.cgi">
<input type=text name="birthyear">
<input type=submit name=press value="OK">
</form></code></span></span>
在您喜欢的浏览器中,此表单将显示一个文本框以供填写,并带有一个标有“确定”的按钮。如果您填写“1905”并按 OK 按钮,您的浏览器将创建一个新的 URL 来为您获取。该 URL 将junk.cgi?birthyear=1905&press=OK
附加到前一个 URL 的路径部分。
如果在页面上看到原始表单www.example.com/when/birth.html
,您将获得的第二页将变为www.example.com/when/junk.cgi?birthyear=1905&press=OK
。
大多数搜索引擎都是这样工作的。
要让 curl 为您发送 GET 表单,只需输入预期的创建 URL:
curl "http://www.example.com/when/junk.cgi?birthyear=1905&press=OK"
邮政
GET 方法使所有输入字段名称都显示在浏览器的 URL 字段中。当您希望能够使用给定数据为该页面添加书签时,这通常是一件好事,但如果您在其中一个字段中输入了秘密信息,或者如果有大量字段创建了一个长且不可读的网址。
然后 HTTP 协议提供 POST 方法。这样,客户端发送的数据与 URL 分开,因此您不会在 URL 地址字段中看到任何数据。
该表单看起来与前一个类似:
<span style="color:#000000"><span style="background-color:#ffffff"><code><form method="POST" action="junk.cgi">
<input type=text name="birthyear">
<input type=submit name=press value=" OK ">
</form></code></span></span>
并且要使用 curl 来发布此表单,并填写与以前相同的数据,我们可以这样做:
curl --data "birthyear=1905&press=%20OK%20" http://www.example.com/when/junk.cgi
这种 POST 将使用 Content-Typeapplication/x-www-form-urlencoded
并且是使用最广泛的 POST 类型。
您发送到服务器的数据必须已经正确编码,curl 不会为您这样做。例如,如果您希望数据包含一个空格,则需要将该空格替换为%20
等。不遵守此规定很可能会导致您的数据被错误接收并弄乱。
最近的 curl 版本实际上可以为您对 POST 数据进行 url 编码,如下所示:
curl --data-urlencode "name=I am Daniel" http://www.example.com
如果您--data
在命令行上重复多次,curl 将连接所有给定的数据段 - 并&
在每个数据段之间放置一个符号。
文件上传 POST
早在 1995 年末,他们就定义了另一种通过 HTTP 发布数据的方式。它记录在 RFC 1867 中,为什么这种方法有时被称为 RFC1867-posting。
该方法主要是为了更好地支持文件上传而设计的。允许用户上传文件的表单可以用 HTML 编写如下:
<span style="color:#000000"><span style="background-color:#ffffff"><code><form method="POST" enctype='multipart/form-data' action="upload.cgi">
<input type=file name=upload>
<input type=submit name=press value="OK">
</form></code></span></span>
这清楚地表明即将发送的 Content-Type 是multipart/form-data
.
要使用 curl 发布到这样的表单,请输入如下命令行:
curl --form upload=@localfilename --form press=OK [URL]
隐藏字段
基于 HTML 的应用程序在页面之间传递状态信息的常用方法是向表单添加隐藏字段。隐藏字段已经填写,它们不会显示给用户,它们会像所有其他字段一样被传递。
具有一个可见字段、一个隐藏字段和一个提交按钮的类似示例表单可能如下所示:
<span style="color:#000000"><span style="background-color:#ffffff"><code><form method="POST" action="foobar.cgi">
<input type=text name="birthyear">
<input type=hidden name="person" value="daniel">
<input type=submit name="press" value="OK">
</form></code></span></span>
要使用 curl 发布此内容,您无需考虑字段是否隐藏。卷曲它们都是一样的:
curl --data "birthyear=1905&press=OK&person=daniel" [URL]
弄清楚 POST 的样子
当您要填写表单并使用 curl 而不是浏览器将其发送到服务器时,您当然有兴趣完全按照浏览器的方式发送 POST。
一个简单的查看方法是将带有表单的 HTML 页面保存在本地磁盘上,将“方法”修改为 GET,然后按提交按钮(如果需要,您也可以更改操作 URL) .
然后,您将清楚地看到数据被附加到 URL 中,并用 -?
字母分隔,因为 GET 表单应该如此。
HTTP 上传
放
也许将数据上传到 HTTP 服务器的最佳方式是使用 PUT。话又说回来,这当然需要有人在知道如何接收 HTTP PUT 流的服务器端放置一个程序或脚本。
使用 curl 将文件放入 HTTP 服务器:
curl --upload-file uploadfile http://www.example.com/receive.cgi
HTTP 身份验证
基本认证
HTTP 身份验证能够告诉服务器您的用户名和密码,以便它可以验证您是否被允许执行您正在执行的请求。HTTP 中使用的基本身份验证(默认情况下 curl 使用的类型)是基于纯文本的,这意味着它发送的用户名和密码只是稍微混淆,但仍然可以被任何在你和远程服务器之间的网络上嗅探的人完全读取。
告诉 curl 使用用户和密码进行身份验证:
curl --user name:password http://www.example.com
其他认证
该站点可能需要不同的身份验证方法(检查服务器返回的标头),然后--ntlm, --digest,--negotiate甚至--anyauth可能是适合您的选项。
代理身份验证
有时您的 HTTP 访问只能通过使用 HTTP 代理获得。这似乎在各个公司中尤为常见。HTTP 代理可能需要自己的用户名和密码才能允许客户端访问 Internet。要使用 curl 指定那些,请运行以下命令:
curl --proxy-user proxyuser:proxypassword curl.se
如果您的代理需要使用 NTLM 方法完成身份验证,请使用--proxy-ntlm,如果它需要 Digest 使用--proxy-digest。
如果您使用这些用户+密码选项中的任何一个,但省略了密码部分,curl 将交互提示输入密码。
隐藏凭据
请注意,当程序运行时,在列出系统正在运行的进程时,可能会看到它的参数。因此,如果您将密码作为纯命令行选项传递,其他用户可能会看到您的密码。有办法规避这一点。
值得注意的是,虽然这是 HTTP 身份验证的工作方式,但许多网站在提供登录等时不会使用此概念。有关详细信息,请参阅下面的 Web 登录章节。
更多 HTTP 标头
推荐人
HTTP 请求可能包含一个“referer”字段(是的,它拼写错误),可用于判断客户端从哪个 URL 获取到该特定资源。一些程序/脚本会检查请求的引用字段,以验证这不是来自外部站点或未知页面。虽然这是一种检查容易伪造的东西的愚蠢方法,但许多脚本仍然这样做。使用 curl,您可以在引用字段中放入任何您想要的内容,从而更容易欺骗服务器为您的请求提供服务。
使用 curl 设置引用字段:
curl --referer http://www.example.come http://www.example.com
用户代理
与referer 字段类似,所有HTTP 请求都可以设置User-Agent 字段。它命名正在使用的用户代理(客户端)。许多应用程序使用此信息来决定如何显示页面。愚蠢的网络程序员试图为不同浏览器的用户制作不同的页面,以使它们看起来最适合他们的特定浏览器。他们通常也做不同类型的 JavaScript、VBScript 等。
有时,您会看到使用 curl 获取页面不会返回您在使用浏览器获取页面时看到的相同页面。然后你知道是时候设置用户代理字段来欺骗服务器,让服务器认为你是那些浏览器之一。
要使 curl 在 Windows 2000 机器上看起来像 Internet Explorer 5:
curl --user-agent "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" [URL]
或者为什么不看起来像在旧的 Linux 机器上使用 Netscape 4.73:
curl --user-agent "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" [URL]
重定向
位置标头
当从服务器请求资源时,来自服务器的回复可能包括关于浏览器下一步应该去哪里找到该页面的提示,或者一个新页面保留新生成的输出。告诉浏览器重定向的标头是Location:
.
默认情况下, Curl 不跟随Location:
标头,而是以与显示所有 HTTP 回复相同的方式简单地显示此类页面。但是,它确实具有一个选项,可以使它尝试跟随Location:
指针。
告诉 curl 跟随一个位置:
curl --location http://www.example.com
如果您使用 curl 发布到一个立即将您重定向到另一个页面的站点,您可以安全地使用--location( -L
) 和--data
/--form
一起。Curl 只会在第一个请求中使用 POST,然后在以下操作中恢复为 GET。
其他重定向
浏览器通常支持至少两种 curl 不支持的其他重定向方式:首先,html 可能包含一个元刷新标签,要求浏览器在设定的秒数后加载特定的 URL,或者它可能使用 JavaScript 来完成。
饼干
饼干基础
Web 浏览器执行“客户端状态控制”的方式是使用 cookie。Cookie 只是带有相关内容的名称。cookie 由服务器发送给客户端。服务器告诉客户端它想要返回 cookie 的路径和主机名,它还发送一个过期日期和更多属性。
当客户端使用先前在接收到的 cookie 中指定的名称和路径与服务器通信时,客户端将 cookie 及其内容发送回服务器,当然除非它们已过期。
许多应用程序和服务器使用此方法将一系列请求连接到单个逻辑会话中。为了能够在这种情况下使用 curl,我们必须能够以 Web 应用程序期望的方式记录和发送回 cookie。浏览器处理它们的方式相同。
饼干选项
使用 curl 获取页面时向服务器发送一些 cookie 的最简单方法是在命令行中添加它们,例如:
curl --cookie "name=Daniel" http://www.example.com
Cookies 作为常见的 HTTP 标头发送。这是实用的,因为它允许 curl 仅通过记录标题来记录 cookie。使用--dump-header( -D
) 选项使用 curl 记录 cookie,例如:
curl --dump-header headers_and_cookies http://www.example.com
(请注意,--cookie-jar下面描述的选项是存储 cookie 的更好方法。)
如果您想重新连接到服务器并使用从先前连接中存储的 cookie(或手动制作以欺骗服务器相信您有先前的连接,Curl 内置了一个完整的 cookie 解析引擎,则可以使用该引擎)。要使用以前存储的 cookie,您可以运行 curl,如下所示:
curl --cookie stored_cookies_in_file http://www.example.com
--cookie当您使用该选项时,Curl 的“cookie 引擎”将被启用。如果您只想让 curl 了解收到的 cookie,请使用--cookie
不存在的文件。例如,如果你想让 curl 理解来自页面的 cookie 并跟踪一个位置(因此可能会发回它收到的 cookie),你可以像这样调用它:
curl --cookie nada --location http://www.example.com
Curl 能够读取和写入使用 Netscape 和 Mozilla 曾经使用的相同文件格式的 cookie 文件。这是在脚本或调用之间共享 cookie 的便捷方式。( --cookie
)-b
开关自动检测给定文件是否是这样的 cookie 文件并对其进行解析,并且通过使用--cookie-jar
( -c
) 选项,您将使 curl 在操作结束时写入一个新的 cookie 文件:
curl --cookie cookies.txt --cookie-jar newcookies.txt http://www.example.com
HTTPS
HTTPS 是 HTTP 安全的
有几种方法可以进行安全的 HTTP 传输。到目前为止,最常用的协议是通常称为 HTTPS、HTTP over SSL 的协议。SSL 对通过网络发送和接收的所有数据进行加密,从而使攻击者更难窥探敏感信息。
SSL(或称为该标准的最新版本的 TLS)提供了大量高级功能,以允许加密 HTTP 所需的所有加密和关键基础设施机制。
当构建使用 TLS 库时,Curl 支持加密提取,并且可以构建它以使用相当大的一组库中的curl -V
一个 - 将显示您的 curl 是为使用哪个库而构建的(如果有的话!)。要从 HTTPS 服务器获取页面,只需运行 curl,如下所示:
curl https://secure.example.com
证书
在 HTTPS 世界中,您使用证书来验证您是您声称的那个人,作为普通密码的补充。Curl 支持客户端证书。所有证书都使用密码锁定,您需要输入密码才能让 curl 使用证书。密码短语可以在命令行中指定,如果没有,则在 curl 查询时以交互方式输入。在 HTTPS 服务器上使用带有 curl 的证书,例如:
curl --cert mycert.pem https://secure.example.com
curl 还尝试通过根据本地存储的 CA 证书包验证服务器的证书来验证服务器是否是它声称的身份。验证失败将导致 curl 拒绝连接。然后您必须使用--insecure( -k
) 以防您想告诉 curl 忽略无法验证服务器。
有关服务器证书验证和 ca 证书捆绑的更多信息,请参阅SSLCERTS 文档。
有时您可能会得到自己的 CA 证书存储,然后您可以告诉 curl 使用它来验证服务器的证书:
curl --cacert ca-bundle.pem https://example.com/
自定义请求元素
修改方法和标头
做一些花哨的事情,您可能需要添加或更改单个 curl 请求的元素。
例如,您可以将 POST 请求更改为 PROPFIND 并将数据发送为Content-Type: text/xml
(而不是默认的 Content-Type),如下所示:
curl --data "<xml>" --header "Content-Type: text/xml" --request PROPFIND example.com
您可以通过提供没有内容的默认标题来删除默认标题。就像您可以通过切断 Host: 标头来破坏请求一样:
curl --header "Host:" http://www.example.com
您可以以相同的方式添加标题。您的服务器可能需要一个Destination:
标头,您可以添加它:
curl --header "Destination: http://nowhere" http://example.com
更多关于改变方法
需要注意的是,curl 根据请求的操作自行选择使用哪些方法。-d
会做 POST,-I
会做 HEAD 等等。如果使用--request/-X
选项,您可以更改 curl 选择的方法关键字,但不会修改 curl 的行为。这意味着如果您例如使用 -d "data" 进行 POST,您可以将方法修改为PROPFIND
with-X
并且 curl 仍会认为它发送 POST 。-X POST
您可以通过简单地添加如下命令行将普通 GET 更改为 POST 方法:
curl -X POST http://example.org/
...但是 curl 仍然会像发送 GET 一样思考和行动,因此它不会发送任何请求正文等。
网页登录
一些登录技巧
虽然不仅仅是与 HTTP 相关,但它仍然会给很多人带来问题,所以这里是关于绝大多数登录表单如何工作以及如何使用 curl 登录到它们的执行概要。
还可以注意到,要以自动化方式正确执行此操作,您肯定需要编写脚本并执行多个 curl 调用等。
首先,服务器主要使用 cookie 来跟踪客户端的登录状态,因此您需要捕获在响应中收到的 cookie。然后,许多网站还在登录页面上设置了一个特殊的 cookie(以确保您通过他们的登录页面到达那里),因此您应该养成首先获取登录表单页面以捕获那里设置的 cookie 的习惯。
一些基于 Web 的登录系统具有不同数量的 JavaScript,有时它们使用此类代码来设置或修改 cookie 内容。可能他们这样做是为了防止编程登录,就像本手册描述了如何......无论如何,如果阅读代码不足以让您手动重复该行为,那么捕获浏览器完成的 HTTP 请求并分析发送的 cookie 通常是一种工作方法,用于解决如何缩短 JavaScript 所需的时间。
在登录的实际<form>
标签中,许多网站填写随机/会话或其他秘密生成的隐藏标签,您可能需要先捕获登录表单的 HTML 代码并提取所有隐藏字段才能正确执行登录 POST。请记住,在普通 POST 中发送时,内容需要进行 URL 编码。
调试
一些调试技巧
很多时候,当您在站点上运行 curl 时,您会注意到该站点对您的 curl 请求的响应方式似乎与它对浏览器的响应方式不同。
然后你需要开始让你的 curl 请求更类似于浏览器的请求:
-
使用该--trace-ascii
选项来存储请求的完整详细日志,以便于分析和更好地理解
-
确保在需要时检查并使用 cookie(阅读--cookie
和写作--cookie-jar
)
-
将 user-agent (with -A) 设置为一个,就像最近流行的浏览器一样
-
-E像浏览器设置的那样设置引用者(带)
-
如果您使用 POST,请确保以与浏览器相同的顺序发送所有字段。
检查浏览器的功能
确保您正确执行此操作的一个好帮手是 Web 浏览器的开发人员工具,可让您查看您发送和接收的所有标头(即使使用 HTTPS)。
更原始的方法是使用 Wireshark 或 tcpdump 等工具捕获网络上的 HTTP 流量,并检查浏览器发送和接收的标头。(HTTPS 强制您使用它SSLKEYLOGFILE
来执行此操作。)
看过我自己写的请求,只是基础使用,具体的方式都在curl官网,教程操作文档很全,我介绍了我们常用使用curl的方式,当然还有证书,代理,其他协议的使用,感兴趣的可以自己去官网研究下,curl支持脚本方式调用,不仅仅支持xshell脚本,还有代码。