Ruby on rails 联系第三方API时的错误处理

Ruby on rails 联系第三方API时的错误处理,ruby-on-rails,ruby,exception,error-handling,Ruby On Rails,Ruby,Exception,Error Handling,假设我在Rails控制器中有以下人工代码: class ProfilesController < ApplicationController def show @profile = current_user.profile @content_from_third_party_api = @profile.get_that_third_party_content end end 这是为#获取第三方内容#设计的代码: def get_that_third_party_

假设我在Rails控制器中有以下人工代码:

class ProfilesController < ApplicationController
  def show
    @profile = current_user.profile
    @content_from_third_party_api = @profile.get_that_third_party_content
  end
end
这是为
#获取第三方内容
#设计的代码:

def get_that_third_party_content
  uri = URI.parse("http://api.somesite.com/imfake/")

  http = Net::HTTP.new(uri.host, uri.port)
  request = Net::HTTP::Get.new(uri.request_uri)
  response = http.request(request)

  case response.code.to_i
  when 200 # the happy path
    response
  when (400..499)
    # What should I do/return here?  I have nothing useful to return to the caller.
  when (500..599)
    # Same goes for here...
  end
end
我如何优雅地处理
中的超时/错误/etc,获取第三方内容
如下:

  • show视图期望来自第三方api的
    @content\u不为零。如果是零,我会得到零级错误到处都是
  • show视图需要渲染某些内容
  • #获取第三方内容
    如果出现错误,则不会返回任何内容
  • 感觉我需要做很多零检查。。。这似乎真的错了
  • rescue\u from
    似乎是一个好的解决方案,但我不确定这是否好

您可能希望使用类似于此处的东西,因为您可以利用中间件。创建法拉第生成器相当简单,您可以编写中间件来处理所有问题。有用于超时(只需要它)和异常处理的本机中间件

鉴于您希望“优雅地”处理这些用例,中间件似乎是我最合乎逻辑的选择。否则,正如您所指出的,您的控制器中将有复杂的分支逻辑

# lib/requestor.rb
require 'faraday'
require 'faraday_middleware' # optional, but nice: https://github.com/lostisland/faraday_middleware

# This is just one example. There are literally hundreds of ways to use
# Faraday, and the documentation is quite good.
class APIConnector
  attr_reader :connection

  def initialize(url)
    @connection = Faraday.new(url) do |connection|
      # Set up your connection here (like response and request objects).
      # There are a lot of examples in the Faraday documentation and things
      # really depend on the API you are accessing.
      #
      # You can set things like timeouts, retrys, mashes, rashes, etc.

      # Set some options, such as timeouts
      connection.options[:timeout]      = 10
      connection.options[:open_timeout] = 10
    end
  end

  def get(path)
    connection.get(path)
  end
end
然后在控制器中:

class ProfilesController < ApplicationController
  def show
    @profile = current_user.profile
    response = requestor.get('/path')

    if response.success?
      @third_party_content = response.body
    else
      # This changes depending on the volatility of your application. 
      # You might raise an error, show a flash message, kill the 
      # request, etc. It all depends on the context.
      render text: 'API Request failed'
    end
  end

  private

  def requestor
    @requestor ||= Requestor.new(some_url)
  end
end
class ProfilesController
如果超时,
将呈现另一个页面,说明出现了问题,并稍后重试。您还可以存储从这些API收到的任何信息,并在超时、出错等情况下返回存储的信息。是否有用于此的模式?感谢您的回答,但可以使用的代码示例和/或模式将非常有用。非常感谢!因此,可以安全地说,无论发生什么情况,至少有一个逻辑分支基本上检查请求是否失败,然后呈现一些内容供用户查看?我问这个问题是因为在研究这个问题时,我看到很多人使用
rescue\u from
并提出了一个特定的错误。这似乎可以让控制器的动作不受逻辑的影响。对-你至少需要一个。除非您将其下推到中间件堆栈中并引发异常。然后由处理人员进行全球救援,优雅地解决了这一问题,非常感谢更新答案!我一直在读你的博客文章,希望你能帮我解决这个问题,我意识到你也在这里回答我的问题!:)在选择正确答案之前,我有两个要求:1-我认为应该检查
APIConnector
#get
#initialize
中,
连接
应该是
@connection
?2-如何使用本机中间件进行超时?更新以包含超时示例。修复了嵌套,但连接正确(顶部有一个属性读取器)
class ProfilesController < ApplicationController
  def show
    @profile = current_user.profile
    response = requestor.get('/path')

    if response.success?
      @third_party_content = response.body
    else
      # This changes depending on the volatility of your application. 
      # You might raise an error, show a flash message, kill the 
      # request, etc. It all depends on the context.
      render text: 'API Request failed'
    end
  end

  private

  def requestor
    @requestor ||= Requestor.new(some_url)
  end
end