Ruby on rails 联系第三方API时的错误处理
假设我在Rails控制器中有以下人工代码: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_
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