Ruby Net::HTTP
教程
在本教程中,我们展示了如何使用标准的 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 会自动选择默认 WEBrick 服务器上的 Thin。
$ pwd
/home/janbodnar/prog/sinatra/first
$ ls
main.rb
在第一个目录中,我们有一个main.rb
文件,它是 Sinatra 应用文件。
main.rb
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
命令启动应用。 瘦服务器启动; 它在 4567 端口上监听。
$ curl localhost:4567/
First application
使用curl
命令行工具,我们连接到服务器并访问/
路由。 一条消息出现在控制台上。
版本
第一个程序确定库的版本。
version.rb
#!/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
是一种高级方法,可从目标获取正文并将其输出到标准输出。
get_content.rb
#!/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 标签。
strip_tags.rb
#!/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
方法给出其状态。
status.rb
#!/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
使用message
和code
方法检查 HTTP 响应的状态。
$ ./status.rb
OK
200
Not Found
404
Found
302
200 是对成功的 HTTP 请求的标准响应,404 指示找不到请求的资源,302 指示该资源已临时重定向。
head
方法
head
方法检索文档标题。 标头由字段组成,包括日期,服务器,内容类型或上次修改时间。
head.rb
#!/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 方法请求指定资源的表示形式。
main.rb
require 'sinatra'
get '/greet' do
"Hello #{params[:name]}"
end
这是 Sinatra 应用文件。 收到/greet
路由后,它将返回一条消息,其中包含客户端发送的名称。
mget.rb
#!/usr/bin/ruby
require 'net/http'
uri = URI "http://localhost: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
在瘦服务器的此日志中,我们可以看到参数已编码到 URL 中。
我们可以直接将参数放入 URL 字符串中。
mget2.rb
#!/usr/bin/ruby
require 'net/http'
uri = URI "http://localhost:4567/greet?name=Peter"
puts Net::HTTP.get uri
这是发出 GET 消息的另一种方式。 它基本上与前面的示例相同。
$ ./mget2.rb
Hello Peter
This is the output of the example.
用户代理
在本节中,我们指定用户代理的名称。
main.rb
require 'sinatra'
get '/agent' do
request.user_agent
end
Sinatra 应用返回客户端发送的用户代理。
agent.rb
#!/usr/bin/ruby
require 'net/http'
uri = URI "http://localhost: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
方法
post
方法在给定的 URL 上调度 POST 请求,为填写的表单内容提供键/值对。
main.rb
require 'sinatra'
post '/target' do
"Hello #{params[:name]}"
end
Sinatra 应用在/target
路由上返回问候语。 它从params
哈希中获取值。
mpost.rb
#!/usr/bin/ruby
require 'net/http'
uri = URI "http://localhost:4567/target"
params = { :name => 'Peter' }
res = Net::HTTP.post_form uri, params
puts res.body
脚本使用具有Peter
值的name
键发送请求。 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
包。 可以使用sudo gem install nokogiri
命令安装。
get_term.rb
#!/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 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。
$ sudo gem install json
如果以前没有安装过,则必须安装json
包。
main.rb
require 'sinatra'
require 'json'
get '/example.json' do
content_type :json
{ :name => 'Jane', :age => 17 }.to_json
end
Sinatra 应用发送 JSON 数据。 它使用to_json
方法完成工作。
parse_json.rb
#!/usr/bin/ruby
require 'net/http'
require 'json'
uri = URI 'http://localhost: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
This is the output of the example.
接下来,我们从 Ruby 脚本将 JSON 数据发送到 Sinatra 应用。
main.rb
require 'sinatra'
require 'json'
post '/readjson' do
data = JSON.parse request.body.read
"#{data["name"]} is #{data["age"]} years old"
end
该应用读取 JSON 数据并发送回带有已解析值的消息。
post_json.rb
#!/usr/bin/ruby
require 'net/http'
require 'json'
uri = URI 'http://localhost: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
该脚本将 JSON 数据发送到 Sinatra 应用并读取其响应。
req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'}
'application/json'
内容类型必须在请求的标头中指定。
$ ./post_json.rb
Jane is 17 years old
This is the output of the example.
重定向
重定向是将一个 URL 转发到另一个 URL 的过程。 HTTP 响应状态代码 302 用于临时 URL 重定向。
main.rb
require 'sinatra'
get "/oldpage" do
redirect to("/files/newpage.html"), 302
end
在 Sinatra 应用中,我们使用redirect
命令重定向到其他位置。
newpage.html
<!DOCTYPE html>
<html>
<head>
<title>New page</title>
</head>
<body>
<p>
This is a new page
</p>
</body>
</html>
这是位于public/files
子目录中的newpage.html
文件。
redirect.rb
#!/usr/bin/ruby
require 'net/http'
uri = URI 'http://localhost: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']
标头的位置字段包含文件重定向到的地址。
$ ./redirect.rb
<!DOCTYPE html>
<html>
<head>
<title>New page</title>
</head>
<body>
<p>
This is a new page
</p>
</body>
</html>
This is the output of the example.
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
包。
main.rb
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 应用中,我们指定授权逻辑并设置受保护的路由。
credentials.rb
#!/usr/bin/ruby
require 'net/http'
uri = URI 'http://localhost: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 教程。