Ruby Net::HTTP 教程
最后修改于 2023 年 1 月 10 日
在本教程中,我们将介绍如何使用标准的 Ruby Net::HTTP 模块。我们将获取数据、发布数据、处理 JSON 并连接到安全的网页。本教程在几个示例中使用了 Sinatra 应用程序。ZetCode 还有一个简洁的 Ruby 教程。
超文本传输协议 (HTTP) 是一种用于分布式、协作式、超媒体信息系统的应用协议。HTTP 是万维网数据通信的基础。
Ruby Net::HTTP
提供了一个丰富的库,可用于构建 HTTP 客户端。
Sinatra
Sinatra 是一个流行的 Ruby Web 应用程序框架。它易于安装和设置。我们的一些示例也将使用 Sinatra 应用程序。
$ sudo gem install sinatra $ sudo gem install thin
我们安装 Sinatra 和 Thin Web 服务器。如果安装了 Thin,Sinatra 会自动选择 Thin 而不是默认的 WEBrick 服务器。
$ pwd /home/janbodnar/prog/sinatra/first $ ls main.rb
在第一个目录中,我们有一个 main.rb
文件,它是 Sinatra 应用程序文件。
require 'sinatra' get '/' do "First application" end
该应用程序响应 /
路由。它将一个简单的消息发送回客户端。
$ ruby main.rb == Sinatra (v1.4.7) has taken the stage on 4567 for development with backup from Thin Thin web server (v1.6.4 codename Gob Bluth) Maximum connections set to 1024 Listening on localhost:4567, CTRL+C to stop
应用程序通过 ruby main.rb
命令启动。Thin 服务器将被启动;它监听 4567 端口。
$ curl localhost:4567/ First application
使用 curl
命令行工具,我们连接到服务器并访问 /
路由。控制台会显示一条消息。
版本
第一个程序确定库的版本。
#!/usr/bin/ruby require 'net/http' puts Net::HTTP::version_1_1? puts Net::HTTP::version_1_2?
该脚本确定 net/http
是在 1.1 还是 1.2 模式下运行。
$ ./version.rb false true
在我们的例子中,模式是 1.2。
获取内容
get_print
是一个高级方法,它获取目标的主体文本并将其输出到标准输出。
#!/usr/bin/ruby require 'net/http' uri = URI 'http://www.something.com/' Net::HTTP.get_print uri
该脚本抓取 www.something.com
网页的内容。net/http
设计用于与 uri
模块紧密配合。
require 'net/http'
这也会需要 uri
,所以我们不需要单独加载它。
$ ./get_content.rb <html><head><title>Something.</title></head> <body>Something.</body> </html>
这是 get_content.rb
脚本的输出。
以下程序获取一个小型网页并去除其 HTML 标签。
#!/usr/bin/ruby require 'net/http' uri = URI "http://www.something.com/" doc = Net::HTTP.get uri puts doc.gsub %r{</?[^>]+?>}, ''
该脚本剥离了 www.something.com
网页的 HTML 标签。
puts doc.gsub %r{</?[^>]+?>}, ''
使用一个简单的正则表达式来去除 HTML 标签。
$ ./strip_tags.rb Something. Something.
该脚本打印网页的标题和内容。
状态
响应的 code
和 message
方法提供了其状态。
#!/usr/bin/ruby require 'net/http' uri = URI 'http://www.something.com' res = Net::HTTP.get_response uri puts res.message puts res.code uri = URI 'http://www.something.com/news/' res = Net::HTTP.get_response uri puts res.message puts res.code uri = URI 'http://www.urbandicionary.com/define.php?term=Dog' res = Net::HTTP.get_response uri puts res.message puts res.code
我们使用 get_response
方法执行三个 HTTP 请求并检查返回的状态。
uri = URI 'http://www.something.com/news/' res = Net::HTTP.get_response uri puts res.message puts res.code
HTTP 响应的状态通过 message
和 code
方法进行检查。
$ ./status.rb OK 200 Not Found 404 Found 302
200 是成功 HTTP 请求的标准响应,404 表示找不到请求的资源,302 表示资源被暂时重定向。
head 方法
head
方法检索文档头信息。头信息由字段组成,包括日期、服务器、内容类型或最后修改时间。
#!/usr/bin/ruby require 'net/http' uri = URI "http://www.something.com" http = Net::HTTP.new uri.host, uri.port res = http.head '/' puts res['server'] puts res['date'] puts res['last-modified'] puts res['content-type'] puts res['content-length']
该示例打印 www.something.com
网页的服务器、日期、最后修改时间、内容类型和内容长度。
$ ./head.rb Apache/2.4.12 (FreeBSD) OpenSSL/1.0.1l-freebsd mod_fastcgi/mod_fastcgi-SNAP-0910052141 Wed, 11 May 2016 19:30:56 GMT Mon, 25 Oct 1999 15:36:02 GMT text/html 77
这是 head.rb
程序的输出。
get 方法
get
方法向服务器发出 GET 请求。GET 方法请求指定资源的表示形式。
require 'sinatra' get '/greet' do "Hello #{params[:name]}" end
这是 Sinatra 应用程序文件。在收到 /greet
路由后,它会返回一条包含客户端发送的名称的消息。
#!/usr/bin/ruby require 'net/http' uri = URI "https://:4567/greet" params = { :name => 'Peter' } uri.query = URI.encode_www_form params puts Net::HTTP.get uri
该脚本将一个带有值的变量发送到 Sinatra 应用程序。该变量直接在 URL 中指定。
params = { :name => 'Peter' }
这是我们发送给服务器的参数。
uri.query = URI.encode_www_form params
我们使用 encode_www_form
方法将参数编码到 URL 中。
puts Net::HTTP.get uri
get
方法向服务器发送 GET 请求。它返回响应,响应被打印到控制台。
$ ./mget.rb Hello Peter
这是示例的输出。
127.0.0.1 - - [11/May/2016:21:51:12 +0200] "GET /greet?name=Peter HTTP/1.1" 200 11 0.0280
在 Thin 服务器的此日志中,我们可以看到参数已被编码到 URL 中。
我们可以直接将参数放入 URL 字符串中。
#!/usr/bin/ruby require 'net/http' uri = URI "https://:4567/greet?name=Peter" puts Net::HTTP.get uri
这是发出 GET 消息的另一种方式;它与前面的示例基本相同。
$ ./mget2.rb Hello Peter
这是示例的输出。
用户代理
在本节中,我们指定了用户代理的名称。
require 'sinatra' get '/agent' do request.user_agent end
Sinatra 应用程序返回客户端发送的用户代理。
#!/usr/bin/ruby require 'net/http' uri = URI "https://:4567" http = Net::HTTP.new uri.host, uri.port res = http.get '/agent', {'User-Agent' => 'Ruby script'} puts res.body
此脚本向 Sinatra 应用程序创建了一个简单的 GET 请求。
res = http.get '/agent', {'User-Agent' => 'Ruby script'}
用户代理在 get
方法的第二个参数中指定。
$ ./agent.rb Ruby script
服务器响应了我们随请求发送的代理名称。
发布一个值
post
方法在给定的 URL 上分派一个 POST 请求,为表单填写内容提供键/值对。
require 'sinatra' post '/target' do "Hello #{params[:name]}" end
Sinatra 应用程序在 /target
路由上返回问候语。它从 params
哈希中获取值。
#!/usr/bin/ruby require 'net/http' uri = URI "https://:4567/target" params = { :name => 'Peter' } res = Net::HTTP.post_form uri, params puts res.body
该脚本发送一个键为 name
、值为 Peter
的请求。POST 请求使用 Net::HTTP.post_form
方法发出。
$ ./mpost.rb Hello Peter
这是 mpost.rb
脚本的输出。
127.0.0.1 - - [12/May/2016:11:36:16 +0200] "POST /target HTTP/1.1" 200 11 0.0006
使用 POST 方法时,值不会发送在请求 URL 中。
从字典中检索定义
在下面的示例中,我们在 www.dictionary.com 上查找一个词的定义。要解析 HTML,我们使用 nokogiri
gem。它可以使用 sudo gem install nokogiri
命令安装。
#!/usr/bin/ruby require 'net/http' require 'nokogiri' term = 'cat' uri = URI 'http://www.dictionary.com/browse/'+term res = Net::HTTP.get uri doc = Nokogiri::HTML res doc.css("div.def-content").map do |node| s = node.text.strip! s.gsub!(/\s{3,}/, " ") unless (s == nil) puts s unless (s == nil) end
在此脚本中,我们在 www.dictionary.com
上查找 cat 这个词的定义。Nokogiri::HTML
用于解析 HTML 代码。
uri = URI 'http://www.dictionary.com/browse/'+term
要执行搜索,我们将术语附加到 URL 的末尾。
doc = Nokogiri::HTML res doc.css("div.def-content").map do |node| s = node.text.strip! s.gsub!(/\s{3,}/, " ") unless (s == nil) puts s unless (s == nil) end
我们使用 Nokogiri::HTML
类解析内容。定义位于 <div class="def-content">
标签内。我们通过删除多余的空格来改进格式。
JSON
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。它易于人类阅读和编写,也易于机器解析和生成。
$ sudo gem install json
如果我们之前没有安装 json
gem,我们需要安装它。
require 'sinatra' require 'json' get '/example.json' do content_type :json { :name => 'Jane', :age => 17 }.to_json end
Sinatra 应用程序发送 JSON 数据。它使用 to_json
方法来完成此操作。
#!/usr/bin/ruby require 'net/http' require 'json' uri = URI 'https://:4567/example.json' res = Net::HTTP.get uri data = JSON.parse res puts data["name"] puts data["age"]
该示例读取 Sinatra 应用程序发送的 JSON 数据。
$ ./parse_json.rb Jane 17
这是示例的输出。
接下来,我们从 Ruby 脚本向 Sinatra 应用程序发送 JSON 数据。
require 'sinatra' require 'json' post '/readjson' do data = JSON.parse request.body.read "#{data["name"]} is #{data["age"]} years old" end
此应用程序读取 JSON 数据并发送回包含解析值的消息。
#!/usr/bin/ruby require 'net/http' require 'json' uri = URI 'https://:4567/readjson' req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'} req.body = {:name => 'Jane', :age => 17}.to_json res = Net::HTTP.start(uri.hostname, uri.port) do |http| http.request req end puts res.body
此脚本向 Sinatra 应用程序发送 JSON 数据并读取其响应。
req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'}
'application/json'
内容类型必须在请求的标头中指定。
$ ./post_json.rb Jane is 17 years old
这是示例的输出。
重定向
重定向是将一个 URL 转发到另一个 URL 的过程。HTTP 响应状态码 302 用于临时 URL 重定向。
require 'sinatra' get "/oldpage" do redirect to("/files/newpage.html"), 302 end
在 Sinatra 应用程序中,我们使用 redirect
命令重定向到另一个位置。
<!DOCTYPE html> <html> <head> <title>New page</title> </head> <body> <p> This is a new page </p> </body> </html>
这是位于 public/files
子目录中的 newpage.html
文件。
#!/usr/bin/ruby require 'net/http' uri = URI 'https://:4567/oldpage' res = Net::HTTP.get_response uri if res.code == "302" res = Net::HTTP.get_response URI res.header['location'] end puts res.body
此脚本访问旧页面并遵循重定向。请注意,这仅适用于一次重定向。
res = Net::HTTP.get_response URI res.header['location']
标头的 location 字段包含文件被重定向到的地址。
$ ./redirect.rb <!DOCTYPE html> <html> <head> <title>New page</title> </head> <body> <p> This is a new page </p> </body> </html>
这是示例的输出。
127.0.0.1 - - [12/May/2016:12:51:24 +0200] "GET /oldpage HTTP/1.1" 302 - 0.0006 127.0.0.1 - - [12/May/2016:12:51:24 +0200] "GET /files/newpage.html HTTP/1.1" 200 113 0.0006
从日志中我们可以看到请求被重定向到了新的文件名。通信包括两个 GET 请求。
凭据
basic_auth
方法设置用于身份验证域的用户名和密码。安全域是用于保护 Web 应用程序资源的机制。
$ sudo gem install sinatra-basic-auth
对于此示例,我们需要安装 sinatra-basic-auth
gem。
require 'sinatra' require "sinatra/basic_auth" authorize do |username, password| username == "user7" && password == "7user" end get '/' do "hello" end protect do get "/secure" do "This is restricted area" end end
在 Sinatra 应用程序中,我们指定授权逻辑并设置受保护的路由。
#!/usr/bin/ruby require 'net/http' uri = URI 'https://:4567/secure' req = Net::HTTP::Get.new uri.path req.basic_auth 'user7', '7user' res = Net::HTTP.start uri.hostname, uri.port do |http| http.request req end puts res.body
该脚本连接到受保护的网页;它提供访问该页面所需的用户名和密码。
$ ./credentials.rb This is restricted area
使用正确的凭据,credentials.rb
脚本将返回受限制的数据。
在本教程中,我们已经使用了 Ruby net/http
模块。ZetCode 上也有类似的 Ruby HTTPClient 教程 和 Ruby Faraday 教程。