ZetCode

Ruby HTTPClient

最后修改于 2023 年 10 月 18 日

在本文中,我们将介绍如何使用 Ruby HTTPClient 模块。我们将获取数据、发送数据、处理 Cookie 以及连接到安全的网页。ZetCode 还有一个简洁的Ruby 教程

超文本传输协议 (HTTP) 是一种用于分布式、协作式、超媒体信息系统的应用协议。HTTP 是万维网数据通信的基础。

Ruby HTTPClient 提供了通过 HTTP 访问 Web 资源的各种方法。该 gem 由 Hiroshi NAKAMURA 创建。

$ sudo gem install httpclient

可以使用 sudo gem install httpclient 命令安装该模块。

Ruby HTTPClient 版本

第一个程序打印出库和 Ruby 语言的版本。

version.rb
#!/usr/bin/ruby

require 'httpclient'

puts HTTPClient::LIB_NAME
puts HTTPClient::RUBY_VERSION_STRING
puts HTTPClient::VERSION

这三个常量提供了库和 Ruby 的版本号。

$ ./version.rb 
(2.8.3, ruby 2.7.2 (2020-10-01))
ruby 2.7.2 (2020-10-01)
2.8.3

这是该示例的示例输出。

Ruby HTTPClient get_content 函数

get_content 是一个高级方法,用于获取由给定 URL 标识的文档。

get_content.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new
cont = client.get_content 'http://webcode.me'

puts cont

该脚本抓取 webcode.me 网页的内容。

cont = client.get_content 'http://webcode.me'

get_content 方法将结果作为一个字符串返回。

$ ./get_content.rb 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>
    
    <p>
         Hello there. How are you?
    </p>
    
</body>
</html>

这是 get_content.rb 脚本的输出。

以下程序获取一个小型网页并去除其 HTML 标签。

strip_tags.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

client.get_content('http://webcode.me') do |chunk|
    puts chunk.gsub(%r{</?[^>]+?>}, '')
end

该脚本会剥离 webcode.me 网页的 HTML 标签。

client.get_content('http://webcode.me') do |chunk|
    puts chunk.gsub(%r{</?[^>]+?>}, '')
end

使用一个简单的正则表达式来剥离 HTML 标签。在此上下文中,get_content 方法以字符串块的形式返回内容。

Ruby HTTPClient 请求

HTTP 请求(HTTP request)是从客户端发送到浏览器以检索信息或执行某些操作的消息。

HTTPClientrequest 方法创建一个新请求。请注意,HTTPClient 类具有 getpostput 等方法,这些方法可以为我们节省一些输入。

create_request.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new
method = 'GET'
url = URI.parse 'http://webcode.me'

res = client.request method, url
puts res.body

该示例创建了一个 GET 请求并将其发送到 http://webcode.me

method = 'GET'
url = URI.parse 'http://webcode.me'

我们创建了一个请求方法和 URL。

res = client.request method, url

使用 request 方法进行请求。

puts res.body

响应消息的 body 属性包含消息正文。

Ruby HTTPClient 状态

HTTP::Message 表示一个 HTTP 请求或响应。它的 status 方法返回响应的 HTTP 状态码。

status.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

res = client.get 'http://webcode.me'
puts res.status
puts HTTP::Status::successful? res.status

res = client.get 'http://webcode.me/news/'
puts res.status
puts HTTP::Status::successful? res.status

我们使用 get 方法执行三个 HTTP 请求并检查返回的状态。

puts HTTP::Status::successful? res.status

HTTP::Status::successful? 方法用于判断状态码是否表示成功。

$ ./status.rb 
200
true
404
false

200 是成功的 HTTP 请求的标准响应,404 表示找不到请求的资源。

head 方法

head 方法检索文档头信息。头信息由字段组成,包括日期、服务器、内容类型或最后修改时间。

head.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

res = client.head 'http://webcode.me'

puts "Server: " + res.header['Server'][0]
puts "Last modified: " + res.header['Last-Modified'][0]
puts "Content type: " + res.header['Content-Type'][0]
puts "Content length: " + res.header['Content-Length'][0]

该示例打印出 http://webcode.me 网页的服务器、最后修改时间、内容类型和内容长度。

$ ./head.rb 
Server: nginx/1.6.2
Last modified: Sat, 20 Jul 2019 11:49:25 GMT
Content type: text/html
Content length: 348

这是 head.rb 程序的输出。

get 方法

get 方法向服务器发出 GET 请求。GET 方法请求指定资源的表示形式。

public/greet.php
<?php

echo "Hello " . htmlspecialchars($_GET['name']);

greet.php 返回从客户端获取的 name 变量的值。htmlspecialchars 函数将特殊字符转换为 HTML 实体;例如,& 转换为 &amp。

mget.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

res = client.get 'https://:8000/greet.php?name=Jan'

puts res.body

该脚本将一个带有值的变量发送到服务器上的 PHP 脚本。变量直接在 URL 中指定。

$ php -S localhost:8000 -t public

我们启动内置的 Web 服务器。

$ ./mget.rb 
Hello Jan

这是示例的输出。

get 方法接受第二个参数,我们可以在其中指定查询参数。

mget2.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

query = {'name' => 'Jan'}
res = client.get 'https://:8000/greet.php', query

puts res.body

该示例与上一个基本相同。

$ ./mget2.rb 
Hello Jan

这是示例的输出。

Ruby HTTPClient 重定向

重定向(Redirection)是将一个 URL 转发到另一个 URL 的过程。HTTP 响应状态码 301 Moved Permanently 用于永久 URL 重定向。

在下面的示例中,我们使用了 nginx Web 服务器。

location = /oldpage.html {
        return 301 /newpage.html;
}

将这些行添加到 nginx 配置文件中,该文件在 Debian 上位于 /etc/nginx/sites-available/default

$ sudo service nginx restart

编辑完文件后,我们必须重新启动 nginx 才能应用更改。

/var/www/html/newpage.html
<!DOCTYPE html>
<html>

<head>
    <title>New page</title>
</head>

<body>
<p>
    This is a new page
</p>
</body>

</html>

这是位于 nginx 文档根目录下的 newpage.html 文件。

redirect.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

res = client.get 'https:///oldpage.html', :follow_redirect => true
puts res.body

此脚本访问旧页面并跟随重定向。

res = client.get 'https:///oldpage.html', :follow_redirect => true

使用 :follow_redirect 选项来跟随重定向。

$ ./redirect.rb 
<!DOCTYPE html>
<html>
<head>
    <title>New page</title>
</head>

<body>
<p>
    This is a new page
</p>
</body>
</html>

这是示例的输出。

$ sudo tail -2 /var/log/nginx/access.log
::1 - - [16/Nov/2020:14:45:28 +0100] "GET /oldpage.html HTTP/1.1" 301 169 "-" 
    "HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))"
::1 - - [16/Nov/2020:14:45:28 +0100] "GET /newpage.html HTTP/1.1" 200 122 "-" 
    "HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))"

access.log 文件中可以看到,请求被重定向到了一个新的文件名。通信由两个 GET 消息组成。

Ruby HTTPClient 用户代理

在本节中,我们指定了用户代理的名称。

public/user_agent.php
<?php 

echo $_SERVER['HTTP_USER_AGENT'];

在 nginx 文档根目录下,我们有这个简单的 PHP 文件。它返回用户代理的名称。

agent.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new default_header: {"User-Agent" => "Ruby script"}

res = client.get 'https://:8000/user_agent.php'
puts res.body

此脚本向 agent.php 脚本创建一个简单的 GET 请求。

client = HTTPClient.new default_header: {"User-Agent" => "Ruby script"}

HTTPClient 的构造函数中,我们指定了用户代理。

$ ./agent.rb 
Ruby script

服务器响应了我们随请求发送的代理名称。

Ruby HTTPClient post 值

post 方法在给定的 URL 上分派一个 POST 请求,为表单填写内容提供键/值对。

public/target.php
<?php

echo "Hello " . htmlspecialchars($_POST['name']);

在我们的本地 Web 服务器上,我们有这个 target.php 文件。它只是将发布的 قيمة(posted value)打印回客户端。

post_value.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

query = {"name" => "Jan"}
res = client.post 'https://:8000/target.php', query

puts res.body

该脚本发送一个具有 name 键和 Jan 值的请求。POST 请求是通过 post 方法发出的。

$ ./post_value.rb 
Hello Jan

这是输出。

$ sudo tail -1 /var/log/nginx/access.log
::1 - - [16/Nov/2020:14:45:28 +0100] "GET /newpage.html HTTP/1.1" 200 122 "-" 
    "HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))"

使用 POST 方法时,值不会发送在请求 URL 中。

Ruby HTTPClient Cookie

HTTP Cookie(HTTP cookie)是从网站发送的一小块数据,在用户浏览时存储在用户的 Web 浏览器或程序数据子文件夹中。当用户访问网页时,浏览器/程序会将 Cookie 发回服务器,以通知服务器用户的先前活动。Cookie 有有效期。

在收到 HTTP 请求时,服务器可以在响应中发送一个 Set-Cookie 标头。之后,Cookie 值会以 Cookie HTTP 标头形式与发送给同一服务器的每个请求一起发送。

public/cookies.php
<?php

$theme = $_COOKIE['theme'];

if (isset($theme)) {

    echo "Your theme is $theme";
} else {

    echo "You are using default theme";
    setcookie('theme', 'black-and-white', time() + (86400 * 7));
}

这个 PHP 文件读取一个 Cookie。如果 Cookie 不存在,则会创建它。该 Cookie 存储用户的偏好主题。

send_cookie.rb
#!/usr/bin/ruby

require 'httpclient'

url = URI.parse "https://:8000/cookies.php"

cookie = WebAgent::Cookie.new
cookie.name = "theme"
cookie.value = "green-and-black"
cookie.url = url

client = HTTPClient.new
client.cookie_manager.add cookie

res = client.get url
puts res.body

我们创建一个自定义 Cookie 并将其发送到 cookies.php 页面。

cookie = WebAgent::Cookie.new
cookie.name = "theme"
cookie.value = "green-and-black"
cookie.url = url

使用 WebAgent::Cookie 类创建 Cookie。

client = HTTPClient.new
client.cookie_manager.add cookie

将 Cookie 添加到 Cookie 管理器。

$ ./send_cookie.rb 
Your theme is green-and-black

这是示例的输出。

接下来,我们将读取一个 Cookie 并将其本地存储在一个文件中。

read_cookie.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

res = client.get 'https://:8000/cookies.php'

client.set_cookie_store 'cookie.dat'
p res.header["Set-Cookie"]

client.save_cookie_store

此脚本从 PHP 文件读取一个 Cookie 并将其本地存储在 cookie.dat 文件中。

最后,我们读取存储的 Cookie 并将其发送到同一个 PHP 文件。

send_cookie2.rb
#!/usr/bin/ruby

require 'httpclient'

client = HTTPClient.new

cm = HTTPClient::CookieManager.new 'cookie.dat'
cm.load_cookies
client.cookie_manager = cm

res = client.get 'https:///cookies.php'
p res.body

使用 HTTPClient::CookieManager 来读取 Cookie。

$ ./send_cookie.rb 
Unknown key: Max-Age = 604800
"You are using default theme"
$ ./read_cookie.rb 
Unknown key: Max-Age = 604800
["theme=black-and-white; expires=Sun, 15-May-2016 16:00:08 GMT; Max-Age=604800"]
$ ./send_cookie.rb 
"Your theme is black-and-white"

我们运行脚本。根据作者的说法,警告消息可以忽略

Ruby HTTPClient 凭证

客户端的 set_auth 方法设置用于区域(realm)的用户名和密码。安全区域(security realm)是一种用于保护 Web 应用程序资源的机制。

$ sudo apt-get install apache2-utils
$ sudo htpasswd -c /etc/nginx/.htpasswd user7
New password: 
Re-type new password: 
Adding password for user user7

我们使用 htpasswd 工具为基本 HTTP 身份验证创建一个用户名和密码。

location /secure {

        auth_basic "Restricted Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
}

在 nginx 的 /etc/nginx/sites-available/default 配置文件中,我们创建一个受保护的页面。该领域的名称是“Restricted Area”。

/var/www/html/secure/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Secure page</title>
</head>

<body>

<p>
This is a secure page.
</p>

</body>

</html>

/var/www/html/secure/ 目录中,我们有这个 HTML 文件。

credentials.rb
#!/usr/bin/ruby

require 'httpclient'

user = 'user7'
passwd = '7user'

client = HTTPClient.new
client.set_auth 'https:///secure/', user, passwd
cont = client.get_content 'https:///secure/'

puts cont

该脚本连接到受保护的网页;它提供访问该页面所需的用户名和密码。

$ ./credentials.rb 
<!DOCTYPE html>
<html lang="en">
<head>
<title>Secure page</title>
</head>

<body>

<p>
This is a secure page.
</p>

</body>

</html>

使用正确的凭证,我们获取了受保护的页面。

在本文中,我们使用了 Ruby HTTPClient 模块。

作者

我的名字是 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面有十多年的经验。