🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Ruby Faraday 教程 > 原文: [https://zetcode.com/web/rubyfaraday/](https://zetcode.com/web/rubyfaraday/) 在本教程中,我们展示了如何使用 Ruby Faraday 模块。 我们获取数据,发布数据,使用 JSON 并连接到安全的网页。 我们还创建了一个自定义的 Faraday 中间件。 本教程使用 Sinatra 应用作为几个示例。 ZetCode 也有一个简洁的 [Ruby 教程](/lang/rubytutorial/)。 超文本传输​​协议(HTTP)是用于分布式协作超媒体信息系统的应用协议。 HTTP 是万维网数据通信的基础。 Ruby `Faraday`是一个简单,灵活的 HTTP 客户端库,支持多个后端。 Faraday 也是一种中间件。 ```ruby $ sudo gem install faraday ``` 该模块通过`sudo gem install faraday`命令安装。 ## Sinatra Sinatra 是流行的 Ruby Web 应用框架。 它易于安装和设置。 我们的一些示例还将使用 Sinatra 应用。 ```ruby $ sudo gem install sinatra $ sudo gem install thin ``` 我们安装 Sinatra 和 Thin Web 服务器。 如果安装了 Thin,Sinatra 会自动选择默认 WEBrick 服务器上的 Thin。 ```ruby $ pwd /home/janbodnar/prog/sinatra/first $ ls main.rb ``` 在第一个目录中,我们有一个`main.rb`文件,它是 Sinatra 应用文件。 `main.rb` ```ruby require 'sinatra' get '/' do "First application" end ``` 应用对`/`路由做出反应。 它将一条简单的消息发送回客户端。 ```ruby $ 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 端口上监听。 ```ruby $ curl localhost:4567/ First application ``` 使用`curl`命令行工具,我们连接到服务器并访问`/`路由。 一条消息出现在控制台上。 ## 版本 第一个 Faraday 程序将打印库和 Ruby 语言的版本。 `version.rb` ```ruby #!/usr/bin/ruby require 'faraday' puts Faraday::VERSION puts Faraday::default_adapter ``` 这两个常数提供了库的版本号和默认的 Faraday 适配器。 ```ruby $ ./version.rb 0.9.2 net_http ``` 这是字符串的示例输出。 ## 获取内容 `get`方法获取由给定 URL 标识的文档。 `get_content.rb` ```ruby #!/usr/bin/ruby require 'faraday' res = Faraday.get 'http://www.something.com' puts res.body ``` 该脚本获取`www.something.com`网页的内容。 ```ruby $ ./get_content.rb <html><head><title>Something.</title></head> <body>Something.</body> </html> ``` 这是`get_content.rb`脚本的输出。 以下程序获取一个小型网页,并剥离其 HTML 标签。 `strip_tags.rb` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday::Connection.new "http://www.something.com" res = con.get puts res.body.gsub(%r{</?[^>]+?>}, '') ``` 该脚本会剥离`www.something.com`网页的 HTML 标签。 ```ruby puts res.body.gsub(%r{</?[^>]+?>}, '') ``` 一个简单的正则表达式用于剥离 HTML 标记。 ```ruby $ ./strip_tags.rb Something. Something. ``` 该脚本将打印网页的标题和内容。 ## 状态 `Faraday::Response`的`status`方法返回响应的 HTTP 状态代码。 `status.rb` ```ruby #!/usr/bin/ruby require 'faraday' res = Faraday.get 'http://www.something.com' puts res.status puts res.success? res = Faraday.get 'http://www.something.com/news/' puts res.status puts res.success? res = Faraday.get 'http://www.urbandicionary.com/define.php?term=Dog' puts res.status puts res.success? ``` 我们使用`get`方法执行三个 HTTP 请求,并检查返回状态。 ```ruby res = Faraday.get 'http://www.something.com' puts res.status ``` 使用`status`方法检查 HTTP 响应的状态。 ```ruby puts res.success? ``` `success?`方法指示状态代码是否成功。 ```ruby $ ./status.rb 200 true 404 false 302 false ``` 200 是对成功的 HTTP 请求的标准响应,404 指示找不到请求的资源,302 指示该资源已临时重定向。 ## `head`方法 `head`方法检索文档标题。 标头由字段组成,包括日期,服务器,内容类型或上次修改时间。 `head.rb` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday.new :url => "http://www.something.com" res = con.head puts 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`网页的服务器,日期,上次修改时间,内容类型和内容长度。 ```ruby $ ./head.rb Apache/2.4.12 (FreeBSD) OpenSSL/1.0.1l-freebsd mod_fastcgi/mod_fastcgi-SNAP-0910052141 Tue, 10 May 2016 10:19:01 GMT Mon, 25 Oct 1999 15:36:02 GMT text/html 77 ``` 这是`head.rb`程序的输出。 ## `get`方法 `get`方法向服务器发出 GET 请求。 GET 方法请求指定资源的表示形式。 `main.rb` ```ruby require 'sinatra' get '/greet' do "Hello #{params[:name]}" end ``` 这是 Sinatra 应用文件。 收到`/greet`路由后,它将返回一条消息,其中包含客户端发送的名称。 `mget.rb` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday.new res = con.get 'http://localhost:4567/greet', { :name => 'Peter' } puts res.body ``` 该脚本将具有值的变量发送到 Sinatra 应用。 该变量直接在 URL 中指定。 ```ruby $ ./mget.rb Hello Peter ``` 这是示例的输出。 ```ruby 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` ```ruby #!/usr/bin/ruby require 'faraday' res = Faraday.get do |req| req.url 'http://localhost/greet' req.params['name'] = 'Jan' end puts res.body ``` 这是发出 GET 消息的另一种方式。 ```ruby $ ./mget2.rb Hello Peter ``` This is the output of the example. ## 用户代理 在本节中,我们指定用户代理的名称。 `main.rb` ```ruby require 'sinatra' get '/agent' do request.user_agent end ``` Sinatra 应用返回客户端发送的用户代理。 `agent.rb` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday.new res = con.get do |req| req.url 'http://localhost:4567/agent' req.headers['User-Agent'] = 'Ruby script' end puts res.body ``` 该脚本向 Sinatra 应用创建一个简单的 GET 请求。 ```ruby res = con.get do |req| req.url 'http://localhost:4567/agent' req.headers['User-Agent'] = 'Ruby script' end ``` 用户代理在请求的`headers`属性中指定。 ```ruby $ ./agent.rb Ruby script ``` 服务器使用我们随请求发送的代理名称进行了响应。 ## `post`方法 `post`方法在给定的 URL 上调度 POST 请求,为填写的表单内容提供键/值对。 `main.rb` ```ruby require 'sinatra' post '/target' do "Hello #{params[:name]}" end ``` Sinatra 应用在`/target`路由上返回问候语。 它从`params`哈希中获取值。 `mpost.rb` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday.new 'http://localhost' res = con.post '/target', { :name => 'Jan' } puts res.body ``` 脚本使用具有`Jan`值的`name`键发送请求。 POST 请求通过`post`方法发出。 ```ruby $ ./mpost.rb Hello Jan ``` 这是`mpost.rb`脚本的输出。 ```ruby 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](http://www.dictionary.com) 上找到术语的定义。 要解析 HTML,我们使用`nokogiri`。 可以使用`sudo gem install nokogiri`命令安装。 `get_term.rb` ```ruby #!/usr/bin/ruby require 'faraday' require 'nokogiri' term = 'dog' con = Faraday.new :url => 'http://www.dictionary.com/browse/'+term res = con.get doc = Nokogiri::HTML res.body 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`上找到了术语狗的定义。 `Nokogiri::HTML`用于解析 HTML 代码。 ```ruby con = Faraday.new :url => 'http://www.dictionary.com/browse/'+term ``` 为了执行搜索,我们在 URL 的末尾附加了该词。 ```ruby doc = Nokogiri::HTML res.body 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 对象表示法)是一种轻量级的数据交换格式。 人类很容易读写,机器也很容易解析和生成。 ```ruby $ sudo gem install json ``` 如果以前没有安装过,则必须安装`json`包。 `main.rb` ```ruby 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` ```ruby #!/usr/bin/ruby require 'faraday' require 'json' con = Faraday.new :url => 'http://localhost:4567/example.json' res = con.get data = JSON.parse res.body puts data["name"] puts data["age"] ``` 该示例读取 Sinatra 应用发送的 JSON 数据。 ```ruby $ ./parse_json.rb Jane 17 ``` This is the output of the example. 接下来,我们从 Ruby 脚本将 JSON 数据发送到 Sinatra 应用。 `main.rb` ```ruby require 'sinatra' require 'json' post '/readjson' do data = JSON.parse request.body.read puts data "#{data["name"]} is #{data["age"]} years old" end ``` 该应用读取 JSON 数据并发送回带有已解析值的消息。 `post_json.rb` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday.new res = con.post do |req| req.url 'http://localhost:4567/readjson' req.headers['Content-Type'] = 'application/json' req.body = '{ "name": "Jane", "age": 17 }' end puts res.body ``` 该脚本将 JSON 数据发送到 Sinatra 应用并读取其响应。 ```ruby req.headers['Content-Type'] = 'application/json' ``` 必须在请求中指定`'application/json'`内容类型。 ```ruby $ ./post_json.rb Jane is 17 years old ``` This is the output of the example. ## 证书 `basic_auth`方法设置用于领域的名称和密码。 安全领域是一种用于保护 Web 应用资源的机制。 ```ruby $ sudo gem install sinatra-basic-auth ``` 对于此示例,我们需要安装`sinatra-basic-auth`包。 `main.rb` ```ruby 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` ```ruby #!/usr/bin/ruby require 'faraday' con = Faraday.new :url => 'http://localhost/secure/' user = 'user7' passwd = '7user' con.basic_auth user, passwd res = con.get puts res.body ``` 该脚本连接到安全网页; 它提供访问该页面所需的用户名和密码。 ```ruby $ ./credentials.rb This is restricted area ``` 使用正确的凭据,`credentials.rb`脚本返回受限制的数据。 ## Faraday 中间件 中间件是连接两个原本独立的应用的软件。 除了作为 HTTP 客户端之外,Faraday 还充当中间件。 这个概念与 Ruby Rack 非常相似。 `Faraday::Connection`包含一个中间件列表。 Faraday 中间件传递有请求和响应信息的`env`哈希。 中间件可以在执行请求之前和之后操纵此信息。 ### 重定向 重定向是将一个 URL 转发到另一个 URL 的过程。 HTTP 响应状态代码 302 用于临时 URL 重定向。 重定向是在 Faraday 中间件模块之一中实现的。 ```ruby $ sudo gem install faraday_middleware ``` 这些模块在`faraday_middleware`包中可用。 `main.rb` ```ruby require 'sinatra' get "/oldpage" do redirect to("/files/newpage.html"), 302 end ``` 在 Sinatra 应用中,我们使用`redirect`命令重定向到其他位置。 `newpage.html` ```ruby <!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` ```ruby #!/usr/bin/ruby require 'faraday' require 'faraday_middleware' con = Faraday.new 'http://localhost:4567/oldpage' do |con| con.use FaradayMiddleware::FollowRedirects, limit: 5 con.adapter Faraday.default_adapter end res = con.get puts res.body ``` 该脚本访问旧页面并遵循重定向。 ```ruby $ ./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. ```ruby 127.0.0.1 - - [10/May/2016:22:14:16 +0200] "GET /oldpage HTTP/1.1" 302 - 0.0199 127.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` ```ruby require 'sinatra' get '/greet' do "Hello #{params[:name]}" end ``` 这是一个 Sinatra 应用,它向客户端发送问候语。 `logger.rb` ```ruby #!/usr/bin/ruby require 'faraday' require 'logger' class MyLogger def initialize app @app = app @logger = Logger.new(STDOUT) end def call env on_request("request", env) @app.call(env).on_complete do on_response("response", env) end end private def on_request phase, env @logger.info("#{phase} : #{env.method} - #{env.url}") if env.method and env.url end private def on_response phase, env @logger.info("#{phase} : #{env.body}") if env.body end end con = Faraday.new(:url => "http://localhost:4567") do |build| build.request :url_encoded build.use MyLogger build.adapter Faraday.default_adapter end res = con.get "/greet", {'name' => 'Jan'} ``` 在这里,我们创建一个中间件,该中间件实现了对控制台的日志记录。 ```ruby def call env on_request("request", env) @app.call(env).on_complete do on_response("response", env) end end ``` 中间件必须实现`call`方法。 它执行用于请求和响应的方法。 ```ruby private def on_request phase, env @logger.info("#{phase} : #{env.method} - #{env.url}") if env.method and env.url end ``` 生成请求后,将调用`on_request`方法。 该方法记录阶段,请求方法和 URL。 ```ruby con = Faraday.new(:url => "http://localhost:4567") do |build| build.request :url_encoded build.use MyLogger build.adapter Faraday.default_adapter end ``` `MyLogger`中间件通过`use`方法添加到栈中。 当连接对象执行请求时,它将创建一个共享的`env`哈希,将外部中间件包装在每个内部中间件周围,并执行`call`方法。 ```ruby res = con.get "/greet", {'name' => 'Jan'} ``` 一条消息发送到 Sinatra 应用。 该请求和响应被记录到终端。 ```ruby $ ./logger.rb I, [2016-05-11T14:48:55.700198 #4945] INFO -- : request : get - http://localhost:4567/greet?name=Jan I, [2016-05-11T14:48:55.706989 #4945] INFO -- : response : Hello Jan ``` This is the output of the example. 在本教程中,我们使用了 Ruby Faraday 模块。 在 ZetCode 上有类似的 [Ruby HTTPClient 教程](/web/rubyhttpclient/)和 [Ruby Net :: HTTP 教程](/web/rubynethttp/)。