在本教程中,我们展示了如何使用 Ruby Faraday 模块。 我们获取数据,发布数据,使用 JSON 并连接到安全的网页。 我们还创建了一个自定义的 Faraday 中间件。 本教程使用 Sinatra 应用作为几个示例。 ZetCode 也有一个简洁的 Ruby 教程。
超文本传输协议(HTTP)是用于分布式协作超媒体信息系统的应用协议。 HTTP 是万维网数据通信的基础。
Ruby Faraday是一个简单,灵活的 HTTP 客户端库,支持多个后端。 Faraday 也是一种中间件。
$ sudo gem install faraday
该模块通过sudo gem install faraday命令安装。
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$ lsmain.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 ThinThin web server (v1.6.4 codename Gob Bluth)Maximum connections set to 1024Listening on localhost:4567, CTRL+C to stop
使用ruby main.rb命令启动应用。 瘦服务器启动; 它在 4567 端口上监听。
$ curl localhost:4567/First application
使用curl命令行工具,我们连接到服务器并访问/路由。 一条消息出现在控制台上。
版本
第一个 Faraday 程序将打印库和 Ruby 语言的版本。
version.rb
#!/usr/bin/rubyrequire 'faraday'puts Faraday::VERSIONputs Faraday::default_adapter
这两个常数提供了库的版本号和默认的 Faraday 适配器。
$ ./version.rb0.9.2net_http
这是字符串的示例输出。
获取内容
get方法获取由给定 URL 标识的文档。
get_content.rb
#!/usr/bin/rubyrequire 'faraday'res = Faraday.get 'http://www.something.com'puts res.body
该脚本获取www.something.com网页的内容。
$ ./get_content.rb<html><head><title>Something.</title></head><body>Something.</body></html>
这是get_content.rb脚本的输出。
以下程序获取一个小型网页,并剥离其 HTML 标签。
strip_tags.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday::Connection.new "http://www.something.com"res = con.getputs res.body.gsub(%r{</?[^>]+?>}, '')
该脚本会剥离www.something.com网页的 HTML 标签。
puts res.body.gsub(%r{</?[^>]+?>}, '')
一个简单的正则表达式用于剥离 HTML 标记。
$ ./strip_tags.rbSomething.Something.
该脚本将打印网页的标题和内容。
状态
Faraday::Response的status方法返回响应的 HTTP 状态代码。
status.rb
#!/usr/bin/rubyrequire 'faraday'res = Faraday.get 'http://www.something.com'puts res.statusputs res.success?res = Faraday.get 'http://www.something.com/news/'puts res.statusputs res.success?res = Faraday.get 'http://www.urbandicionary.com/define.php?term=Dog'puts res.statusputs res.success?
我们使用get方法执行三个 HTTP 请求,并检查返回状态。
res = Faraday.get 'http://www.something.com'puts res.status
使用status方法检查 HTTP 响应的状态。
puts res.success?
success?方法指示状态代码是否成功。
$ ./status.rb200true404false302false
200 是对成功的 HTTP 请求的标准响应,404 指示找不到请求的资源,302 指示该资源已临时重定向。
head方法
head方法检索文档标题。 标头由字段组成,包括日期,服务器,内容类型或上次修改时间。
head.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday.new :url => "http://www.something.com"res = con.headputs res.headers['server']puts res.headers['date']puts res.headers['last-modified']puts res.headers['content-type']puts res.headers['content-length']
该示例打印www.something.com网页的服务器,日期,上次修改时间,内容类型和内容长度。
$ ./head.rbApache/2.4.12 (FreeBSD) OpenSSL/1.0.1l-freebsd mod_fastcgi/mod_fastcgi-SNAP-0910052141Tue, 10 May 2016 10:19:01 GMTMon, 25 Oct 1999 15:36:02 GMTtext/html77
这是head.rb程序的输出。
get方法
get方法向服务器发出 GET 请求。 GET 方法请求指定资源的表示形式。
main.rb
require 'sinatra'get '/greet' do"Hello #{params[:name]}"end
这是 Sinatra 应用文件。 收到/greet路由后,它将返回一条消息,其中包含客户端发送的名称。
mget.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday.newres = con.get 'http://localhost:4567/greet', { :name => 'Peter' }puts res.body
该脚本将具有值的变量发送到 Sinatra 应用。 该变量直接在 URL 中指定。
$ ./mget.rbHello Peter
这是示例的输出。
127.0.0.1 - - [10/May/2016:22:04:38 +0200] "GET /greet?name=Peter HTTP/1.1" 200 11 0.0034
在瘦服务器的此日志中,我们可以看到参数已编码到 URL 中。
get方法采用第二个参数,我们可以在其中指定查询参数。
mget2.rb
#!/usr/bin/rubyrequire 'faraday'res = Faraday.get do |req|req.url 'http://localhost/greet'req.params['name'] = 'Jan'endputs res.body
这是发出 GET 消息的另一种方式。
$ ./mget2.rbHello Peter
This is the output of the example.
用户代理
在本节中,我们指定用户代理的名称。
main.rb
require 'sinatra'get '/agent' dorequest.user_agentend
Sinatra 应用返回客户端发送的用户代理。
agent.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday.newres = con.get do |req|req.url 'http://localhost:4567/agent'req.headers['User-Agent'] = 'Ruby script'endputs res.body
该脚本向 Sinatra 应用创建一个简单的 GET 请求。
res = con.get do |req|req.url 'http://localhost:4567/agent'req.headers['User-Agent'] = 'Ruby script'end
用户代理在请求的headers属性中指定。
$ ./agent.rbRuby script
服务器使用我们随请求发送的代理名称进行了响应。
post方法
post方法在给定的 URL 上调度 POST 请求,为填写的表单内容提供键/值对。
main.rb
require 'sinatra'post '/target' do"Hello #{params[:name]}"end
Sinatra 应用在/target路由上返回问候语。 它从params哈希中获取值。
mpost.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday.new 'http://localhost'res = con.post '/target', { :name => 'Jan' }puts res.body
脚本使用具有Jan值的name键发送请求。 POST 请求通过post方法发出。
$ ./mpost.rbHello Jan
这是mpost.rb脚本的输出。
127.0.0.1 - - [11/May/2016:13:49:44 +0200] "POST /target HTTP/1.1" 200 9 0.0006
使用 POST 方法时,不会在请求 URL 中发送该值。
从字典中检索定义
在以下示例中,我们在 www.dictionary.com 上找到术语的定义。 要解析 HTML,我们使用nokogiri。 可以使用sudo gem install nokogiri命令安装。
get_term.rb
#!/usr/bin/rubyrequire 'faraday'require 'nokogiri'term = 'dog'con = Faraday.new :url => 'http://www.dictionary.com/browse/'+termres = con.getdoc = Nokogiri::HTML res.bodydoc.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上找到了术语狗的定义。 Nokogiri::HTML用于解析 HTML 代码。
con = Faraday.new :url => 'http://www.dictionary.com/browse/'+term
为了执行搜索,我们在 URL 的末尾附加了该词。
doc = Nokogiri::HTML res.bodydoc.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' docontent_type :json{ :name => 'Jane', :age => 17 }.to_jsonend
Sinatra 应用发送 JSON 数据。 它使用to_json方法完成工作。
parse_json.rb
#!/usr/bin/rubyrequire 'faraday'require 'json'con = Faraday.new :url => 'http://localhost:4567/example.json'res = con.getdata = JSON.parse res.bodyputs data["name"]puts data["age"]
该示例读取 Sinatra 应用发送的 JSON 数据。
$ ./parse_json.rbJane17
This is the output of the example.
接下来,我们从 Ruby 脚本将 JSON 数据发送到 Sinatra 应用。
main.rb
require 'sinatra'require 'json'post '/readjson' dodata = JSON.parse request.body.readputs data"#{data["name"]} is #{data["age"]} years old"end
该应用读取 JSON 数据并发送回带有已解析值的消息。
post_json.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday.newres = con.post do |req|req.url 'http://localhost:4567/readjson'req.headers['Content-Type'] = 'application/json'req.body = '{ "name": "Jane", "age": 17 }'endputs res.body
该脚本将 JSON 数据发送到 Sinatra 应用并读取其响应。
req.headers['Content-Type'] = 'application/json'
必须在请求中指定'application/json'内容类型。
$ ./post_json.rbJane is 17 years old
This is the output of the example.
证书
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"endget '/' do"hello"endprotect doget "/secure" do"This is restricted area"endend
在 Sinatra 应用中,我们指定授权逻辑并设置受保护的路由。
credentials.rb
#!/usr/bin/rubyrequire 'faraday'con = Faraday.new :url => 'http://localhost/secure/'user = 'user7'passwd = '7user'con.basic_auth user, passwdres = con.getputs res.body
该脚本连接到安全网页; 它提供访问该页面所需的用户名和密码。
$ ./credentials.rbThis is restricted area
使用正确的凭据,credentials.rb脚本返回受限制的数据。
Faraday 中间件
中间件是连接两个原本独立的应用的软件。 除了作为 HTTP 客户端之外,Faraday 还充当中间件。 这个概念与 Ruby Rack 非常相似。
Faraday::Connection包含一个中间件列表。 Faraday 中间件传递有请求和响应信息的env哈希。 中间件可以在执行请求之前和之后操纵此信息。
重定向
重定向是将一个 URL 转发到另一个 URL 的过程。 HTTP 响应状态代码 302 用于临时 URL 重定向。
重定向是在 Faraday 中间件模块之一中实现的。
$ sudo gem install faraday_middleware
这些模块在faraday_middleware包中可用。
main.rb
require 'sinatra'get "/oldpage" doredirect to("/files/newpage.html"), 302end
在 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/rubyrequire 'faraday'require 'faraday_middleware'con = Faraday.new 'http://localhost:4567/oldpage' do |con|con.use FaradayMiddleware::FollowRedirects, limit: 5con.adapter Faraday.default_adapterendres = con.getputs res.body
该脚本访问旧页面并遵循重定向。
$ ./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 - - [10/May/2016:22:14:16 +0200] "GET /oldpage HTTP/1.1" 302 - 0.0199127.0.0.1 - - [10/May/2016:22:14:16 +0200] "GET /files/newpage.html HTTP/1.1" 200 113 0.0073
从日志中,我们可以看到该请求已重定向到新的文件名。 通信包含两个 GET 消息。
MyLogger
在以下示例中,我们创建了自己的小型中间件。 它实现了请求和响应日志记录。
main.rb
require 'sinatra'get '/greet' do"Hello #{params[:name]}"end
这是一个 Sinatra 应用,它向客户端发送问候语。
logger.rb
#!/usr/bin/rubyrequire 'faraday'require 'logger'class MyLoggerdef initialize app@app = app@logger = Logger.new(STDOUT)enddef call envon_request("request", env)@app.call(env).on_complete doon_response("response", env)endendprivatedef on_request phase, env@logger.info("#{phase} : #{env.method} - #{env.url}") if env.method and env.urlendprivatedef on_response phase, env@logger.info("#{phase} : #{env.body}") if env.bodyendendcon = Faraday.new(:url => "http://localhost:4567") do |build|build.request :url_encodedbuild.use MyLoggerbuild.adapter Faraday.default_adapterendres = con.get "/greet", {'name' => 'Jan'}
在这里,我们创建一个中间件,该中间件实现了对控制台的日志记录。
def call envon_request("request", env)@app.call(env).on_complete doon_response("response", env)endend
中间件必须实现call方法。 它执行用于请求和响应的方法。
privatedef on_request phase, env@logger.info("#{phase} : #{env.method} - #{env.url}") if env.method and env.urlend
生成请求后,将调用on_request方法。 该方法记录阶段,请求方法和 URL。
con = Faraday.new(:url => "http://localhost:4567") do |build|build.request :url_encodedbuild.use MyLoggerbuild.adapter Faraday.default_adapterend
MyLogger中间件通过use方法添加到栈中。 当连接对象执行请求时,它将创建一个共享的env哈希,将外部中间件包装在每个内部中间件周围,并执行call方法。
res = con.get "/greet", {'name' => 'Jan'}
一条消息发送到 Sinatra 应用。 该请求和响应被记录到终端。
$ ./logger.rbI, [2016-05-11T14:48:55.700198 #4945] INFO -- : request : get - http://localhost:4567/greet?name=JanI, [2016-05-11T14:48:55.706989 #4945] INFO -- : response : Hello Jan
This is the output of the example.
在本教程中,我们使用了 Ruby Faraday 模块。 在 ZetCode 上有类似的 Ruby HTTPClient 教程和 Ruby Net :: HTTP 教程。
