原文: https://zetcode.com/web/rubynethttp/

在本教程中,我们展示了如何使用标准的 Ruby Net::HTTP模块。 我们获取数据,发布数据,使用 JSON 并连接到安全的网页。 本教程使用 Sinatra 应用作为几个示例。 Zetcode 也有一个简洁的 Ruby 教程

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

Ruby Net::HTTP提供了一个丰富的库,可用于构建 HTTP 客户端。

Sinatra

Sinatra 是流行的 Ruby Web 应用框架。 它易于安装和设置。 我们的一些示例还将使用 Sinatra 应用。

  1. $ sudo gem install sinatra
  2. $ sudo gem install thin

我们安装 Sinatra 和 Thin Web 服务器。 如果安装了 Thin,Sinatra 会自动选择默认 WEBrick 服务器上的 Thin。

  1. $ pwd
  2. /home/janbodnar/prog/sinatra/first
  3. $ ls
  4. main.rb

在第一个目录中,我们有一个main.rb文件,它是 Sinatra 应用文件。

main.rb

  1. require 'sinatra'
  2. get '/' do
  3. "First application"
  4. end

应用对/路由做出反应。 它将一条简单的消息发送回客户端。

  1. $ ruby main.rb
  2. == Sinatra (v1.4.7) has taken the stage on 4567 for development with backup from Thin
  3. Thin web server (v1.6.4 codename Gob Bluth)
  4. Maximum connections set to 1024
  5. Listening on localhost:4567, CTRL+C to stop

使用ruby main.rb命令启动应用。 瘦服务器启动; 它在 4567 端口上监听。

  1. $ curl localhost:4567/
  2. First application

使用curl命令行工具,我们连接到服务器并访问/路由。 一条消息出现在控制台上。

版本

第一个程序确定库的版本。

version.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. puts Net::HTTP::version_1_1?
  4. puts Net::HTTP::version_1_2?

该脚本确定net/http是处于 1.1 版还是 1.2 版模式。

  1. $ ./version.rb
  2. false
  3. true

在我们的情况下,模式为 1.2。

获取内容

get_print是一种高级方法,可从目标获取正文并将其输出到标准输出。

get_content.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI 'http://www.something.com/'
  4. Net::HTTP.get_print uri

该脚本获取www.something.com网页的内容。 net/http设计为与uri模块紧密配合。

  1. require 'net/http'

这也需要uri,因此我们不需要单独要求它。

  1. $ ./get_content.rb
  2. <html><head><title>Something.</title></head>
  3. <body>Something.</body>
  4. </html>

这是get_content.rb脚本的输出。

以下程序获取一个小型网页,并剥离其 HTML 标签。

strip_tags.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI "http://www.something.com/"
  4. doc = Net::HTTP.get uri
  5. puts doc.gsub %r{</?[^>]+?>}, ''

该脚本会剥离www.something.com网页的 HTML 标签。

  1. puts doc.gsub %r{</?[^>]+?>}, ''

一个简单的正则表达式用于剥离 HTML 标记。

  1. $ ./strip_tags.rb
  2. Something.
  3. Something.

该脚本将打印网页的标题和内容。

状态

响应的codemessage方法给出其状态。

status.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI 'http://www.something.com'
  4. res = Net::HTTP.get_response uri
  5. puts res.message
  6. puts res.code
  7. uri = URI 'http://www.something.com/news/'
  8. res = Net::HTTP.get_response uri
  9. puts res.message
  10. puts res.code
  11. uri = URI 'http://www.urbandicionary.com/define.php?term=Dog'
  12. res = Net::HTTP.get_response uri
  13. puts res.message
  14. puts res.code

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

  1. uri = URI 'http://www.something.com/news/'
  2. res = Net::HTTP.get_response uri
  3. puts res.message
  4. puts res.code

使用messagecode方法检查 HTTP 响应的状态。

  1. $ ./status.rb
  2. OK
  3. 200
  4. Not Found
  5. 404
  6. Found
  7. 302

200 是对成功的 HTTP 请求的标准响应,404 指示找不到请求的资源,302 指示该资源已临时重定向。

head方法

head方法检索文档标题。 标头由字段组成,包括日期,服务器,内容类型或上次修改时间。

head.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI "http://www.something.com"
  4. http = Net::HTTP.new uri.host, uri.port
  5. res = http.head '/'
  6. puts res['server']
  7. puts res['date']
  8. puts res['last-modified']
  9. puts res['content-type']
  10. puts res['content-length']

该示例打印www.something.com网页的服务器,日期,上次修改时间,内容类型和内容长度。

  1. $ ./head.rb
  2. Apache/2.4.12 (FreeBSD) OpenSSL/1.0.1l-freebsd mod_fastcgi/mod_fastcgi-SNAP-0910052141
  3. Wed, 11 May 2016 19:30:56 GMT
  4. Mon, 25 Oct 1999 15:36:02 GMT
  5. text/html
  6. 77

这是head.rb程序的输出。

get方法

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

main.rb

  1. require 'sinatra'
  2. get '/greet' do
  3. "Hello #{params[:name]}"
  4. end

这是 Sinatra 应用文件。 收到/greet路由后,它将返回一条消息,其中包含客户端发送的名称。

mget.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI "http://localhost:4567/greet"
  4. params = { :name => 'Peter' }
  5. uri.query = URI.encode_www_form params
  6. puts Net::HTTP.get uri

该脚本将具有值的变量发送到 Sinatra 应用。 该变量直接在 URL 中指定。

  1. params = { :name => 'Peter' }

这是我们发送到服务器的参数。

  1. uri.query = URI.encode_www_form params

我们使用encode_www_form方法将参数编码到 URL 中。

  1. puts Net::HTTP.get uri

get方法将 GET 请求发送到服务器。 它返回打印到控制台的响应。

  1. $ ./mget.rb
  2. Hello Peter

这是示例的输出。

  1. 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

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI "http://localhost:4567/greet?name=Peter"
  4. puts Net::HTTP.get uri

这是发出 GET 消息的另一种方式。 它基本上与前面的示例相同。

  1. $ ./mget2.rb
  2. Hello Peter

This is the output of the example.

用户代理

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

main.rb

  1. require 'sinatra'
  2. get '/agent' do
  3. request.user_agent
  4. end

Sinatra 应用返回客户端发送的用户代理。

agent.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI "http://localhost:4567"
  4. http = Net::HTTP.new uri.host, uri.port
  5. res = http.get '/agent', {'User-Agent' => 'Ruby script'}
  6. puts res.body

该脚本向 Sinatra 应用创建一个简单的 GET 请求。

  1. res = http.get '/agent', {'User-Agent' => 'Ruby script'}

用户代理在get方法的第二个参数中指定。

  1. $ ./agent.rb
  2. Ruby script

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

post方法

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

main.rb

  1. require 'sinatra'
  2. post '/target' do
  3. "Hello #{params[:name]}"
  4. end

Sinatra 应用在/target路由上返回问候语。 它从params哈希中获取值。

mpost.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI "http://localhost:4567/target"
  4. params = { :name => 'Peter' }
  5. res = Net::HTTP.post_form uri, params
  6. puts res.body

脚本使用具有Peter值的name键发送请求。 POST 请求通过Net::HTTP.post_form方法发出。

  1. $ ./mpost.rb
  2. Hello Peter

这是mpost.rb脚本的输出。

  1. 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

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. require 'nokogiri'
  4. term = 'cat'
  5. uri = URI 'http://www.dictionary.com/browse/'+term
  6. res = Net::HTTP.get uri
  7. doc = Nokogiri::HTML res
  8. doc.css("div.def-content").map do |node|
  9. s = node.text.strip!
  10. s.gsub!(/\s{3,}/, " ") unless (s == nil)
  11. puts s unless (s == nil)
  12. end

在此脚本中,我们在www.dictionary.com上找到了术语cat的定义。 Nokogiri::HTML用于解析 HTML 代码。

  1. uri = URI 'http://www.dictionary.com/browse/'+term

为了执行搜索,我们在 URL 的末尾附加了该词。

  1. doc = Nokogiri::HTML res
  2. doc.css("div.def-content").map do |node|
  3. s = node.text.strip!
  4. s.gsub!(/\s{3,}/, " ") unless (s == nil)
  5. puts s unless (s == nil)
  6. end

我们使用Nokogiri::HTML类解析内容。 定义位于<div class="def-content">标签内。 我们通过删除过多的空白来改善格式。

JSON 格式

JSON (JavaScript 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。

  1. $ sudo gem install json

如果以前没有安装过,则必须安装json包。

main.rb

  1. require 'sinatra'
  2. require 'json'
  3. get '/example.json' do
  4. content_type :json
  5. { :name => 'Jane', :age => 17 }.to_json
  6. end

Sinatra 应用发送 JSON 数据。 它使用to_json方法完成工作。

parse_json.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. require 'json'
  4. uri = URI 'http://localhost:4567/example.json'
  5. res = Net::HTTP.get uri
  6. data = JSON.parse res
  7. puts data["name"]
  8. puts data["age"]

该示例读取 Sinatra 应用发送的 JSON 数据。

  1. $ ./parse_json.rb
  2. Jane
  3. 17

This is the output of the example.

接下来,我们从 Ruby 脚本将 JSON 数据发送到 Sinatra 应用。

main.rb

  1. require 'sinatra'
  2. require 'json'
  3. post '/readjson' do
  4. data = JSON.parse request.body.read
  5. "#{data["name"]} is #{data["age"]} years old"
  6. end

该应用读取 JSON 数据并发送回带有已解析值的消息。

post_json.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. require 'json'
  4. uri = URI 'http://localhost:4567/readjson'
  5. req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'}
  6. req.body = {:name => 'Jane', :age => 17}.to_json
  7. res = Net::HTTP.start(uri.hostname, uri.port) do |http|
  8. http.request req
  9. end
  10. puts res.body

该脚本将 JSON 数据发送到 Sinatra 应用并读取其响应。

  1. req = Net::HTTP::Post.new uri.path, initheader = {'Content-Type' =>'application/json'}

'application/json'内容类型必须在请求的标头中指定。

  1. $ ./post_json.rb
  2. Jane is 17 years old

This is the output of the example.

重定向

重定向是将一个 URL 转发到另一个 URL 的过程。 HTTP 响应状态代码 302 用于临时 URL 重定向。

main.rb

  1. require 'sinatra'
  2. get "/oldpage" do
  3. redirect to("/files/newpage.html"), 302
  4. end

在 Sinatra 应用中,我们使用redirect命令重定向到其他位置。

newpage.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>New page</title>
  5. </head>
  6. <body>
  7. <p>
  8. This is a new page
  9. </p>
  10. </body>
  11. </html>

这是位于public/files子目录中的newpage.html文件。

redirect.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI 'http://localhost:4567/oldpage'
  4. res = Net::HTTP.get_response uri
  5. if res.code == "302"
  6. res = Net::HTTP.get_response URI res.header['location']
  7. end
  8. puts res.body

该脚本访问旧页面并遵循重定向。 请注意,这适用于单个重定向。

  1. res = Net::HTTP.get_response URI res.header['location']

标头的位置字段包含文件重定向到的地址。

  1. $ ./redirect.rb
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <title>New page</title>
  6. </head>
  7. <body>
  8. <p>
  9. This is a new page
  10. </p>
  11. </body>
  12. </html>

This is the output of the example.

  1. 127.0.0.1 - - [12/May/2016:12:51:24 +0200] "GET /oldpage HTTP/1.1" 302 - 0.0006
  2. 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 应用资源的机制。

  1. $ sudo gem install sinatra-basic-auth

对于此示例,我们需要安装sinatra-basic-auth包。

main.rb

  1. require 'sinatra'
  2. require "sinatra/basic_auth"
  3. authorize do |username, password|
  4. username == "user7" && password == "7user"
  5. end
  6. get '/' do
  7. "hello"
  8. end
  9. protect do
  10. get "/secure" do
  11. "This is restricted area"
  12. end
  13. end

在 Sinatra 应用中,我们指定授权逻辑并设置受保护的路由。

credentials.rb

  1. #!/usr/bin/ruby
  2. require 'net/http'
  3. uri = URI 'http://localhost:4567/secure'
  4. req = Net::HTTP::Get.new uri.path
  5. req.basic_auth 'user7', '7user'
  6. res = Net::HTTP.start uri.hostname, uri.port do |http|
  7. http.request req
  8. end
  9. puts res.body

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

  1. $ ./credentials.rb
  2. This is restricted area

使用正确的凭据,credentials.rb脚本返回受限制的数据。

在本教程中,我们使用了 Ruby net/http模块。 在 ZetCode 上也有类似的 Ruby HTTPClient教程Ruby Faraday 教程