Ruby - 即使抛出了 Stripe 异常,else 块中的代码也会执行

Posted

技术标签:

【中文标题】Ruby - 即使抛出了 Stripe 异常,else 块中的代码也会执行【英文标题】:Ruby - code in else block executes even though Stripe exception WAS thrown 【发布时间】:2015-11-02 21:59:03 【问题描述】:

我的代码的简化版:

1.upto(2) do |try|
  begin
    puts "Start"
  rescue => e
    if try == 2
      puts "Error - #e"
    end
  else
    puts "Success"
  end
end

我的问题是,当我遇到错误时,会发生这种情况:

Start
Start
Error - some message
Success

这里真的让我摸不着头脑,因为这不是应该发生的事情......有什么想法吗?

更新

好的,我认为我通过输入代码的简化版本对自己造成了伤害,因为这可行,但下面的完整版本却不行。即,当 Stripe 抛出 API 异常时,电子邮件仍在触发。

1.upto(2) do |try|
  Stripe.api_key = ENV['Stripe_Secret_Key']
  begin
    customer = Stripe::Customer.create(
      :source => params[:stripeToken],
      :email => @rentalrequest.email
    )
    @charge = Stripe::Charge.create(
      amount: (@rentalrequest.actual_amount * 100), # Stripe requires cents
      currency: "usd",
      customer: customer.id,
      description: "Payment from #@rentalrequest.email for gear rental"
    )
  rescue => e
    if try == 2
      logger.fatal "Stripe error: #e.class, #e.message"
      StripeErrorEmail.new.async.perform(e.class, e.message, @rentalrequest.id)
      render "rental_requests/new" and return
    end
  else
    RoadrunnerEmailAlert.new.async.perform(@rentalrequest.id)
  end
end

换句话说,StripeErrorEmailRoadrunnerEmailAlert 都在开火

更新 KM 的答案

def error_handle(e, id)
  # Since it's a decline, Stripe::CardError will be caught
  body = e.json_body
  err  = body[:error]

  puts "Status is: #e.http_status"
  # => 400
  puts "Type is: #err[:type]"
  # => invalid_request_error
  puts "Code is: #err[:code]"
  # => nil
  puts "Param is: #err[:param]"
  # => nil
  puts "Message is: #err[:message]"
  # => You cannot use a Stripe token more than once

  logger.fatal "Stripe error: #e.class, #e.message"
  StripeErrorEmail.new.async.perform(e.class, e.message, id)
  render "rental_requests/new" and return
end

def charge
  @rentalrequest = RentalRequest.find(params[:rentalrequest_id])

  # Up to two tries
  1.upto(2) do |try|
    Stripe.api_key = ENV['Stripe_Secret_Key']
    begin
      customer = Stripe::Customer.create(
        :source => params[:stripeToken],
        :email => @rentalrequest.email
      )
      @charge = Stripe::Charge.create(
        amount: (@rentalrequest.actual_amount * 100), # Stripe requires cents
        currency: "usd",
        customer: customer.id,
        description: "Payment from #@rentalrequest.email for gear rental"
      )
    rescue Stripe::CardError => e
      if try == 2
        error_handle(e, @rentalrequest.id)
      end
    rescue Stripe::InvalidRequestError => e
      if try == 2
        error_handle(e, @rentalrequest.id)
      end
    rescue Stripe::AuthenticationError => e
      if try == 2
        error_handle(e, @rentalrequest.id)
      end
    rescue Stripe::APIConnectionError => e
      if try == 2
        error_handle(e, @rentalrequest.id)
      end
    rescue Stripe::StripeError => e
      if try == 2
        error_handle(e, @rentalrequest.id)
      end
    rescue => e
      if try == 2
        error_handle(e, @rentalrequest.id)
      end  
    else
      RoadrunnerEmailAlert.new.async.perform
    end
  end
end

【问题讨论】:

你有没有看到错误信息?我在本地尝试过,救援块永远不会执行,因为,没有例外。我建议你看看this post,它对 Ruby begin-rescue 流程有很好的解释。 您希望发生什么? 【参考方案1】:

不,如果出现异常,else 块不会被执行。

我已修改您的代码以引发异常,以便我们对其进行测试:

1.upto(2) do |try|  
  begin
    puts "Start"
    raise 'xxxx'
  rescue => e
    if try == 2
      puts "Error - #e"
    end
  else
    puts "Success"
  end
end

这是输出:

Start
Start
Error - xxxx

这清楚地描述了else块在出现异常时不会被执行。

else 块用于当块完成时没有抛出异常。另一种是ensure,无论块是否成功完成,都会执行。

更新

查看您的最新代码,似乎是条带问题。尝试像这样更优雅地处理条带错误:

begin
  customer = Stripe::Customer.create(
  :source => params[:stripeToken],
  :email => @rentalrequest.email
)

@charge = Stripe::Charge.create(
  amount: (@rentalrequest.actual_amount * 100), # Stripe requires cents
  currency: "usd",
  customer: customer.id,
  description: "Payment from #@rentalrequest.email for gear rental"
)
rescue Stripe::CardError => e
  # Since it's a decline, Stripe::CardError will be caught
  body = e.json_body
  err  = body[:error]

  puts "Status is: #e.http_status"
  puts "Type is: #err[:type]"
  puts "Code is: #err[:code]"
  # param is '' in this case
  puts "Param is: #err[:param]"
  puts "Message is: #err[:message]"
rescue Stripe::InvalidRequestError => e
  # Invalid parameters were supplied to Stripe's API
rescue Stripe::AuthenticationError => e
  # Authentication with Stripe's API failed
  # (maybe you changed API keys recently)
rescue Stripe::APIConnectionError => e
  # Network communication with Stripe failed
rescue Stripe::StripeError => e
  # Display a very generic error to the user, and maybe send
  # yourself an email
rescue => e
  # Something else happened, completely unrelated to Stripe
end

看看能不能解决你的问题。

【讨论】:

是的......这正是应该发生的......但我认为我通过输入简化代码对自己造成了伤害......因为使用你的例子,我也得到了那个结果,但它在我的实际代码中不起作用,我将对其进行修改 @james 查看我编辑的代码,看看是否适合您。如果else 块仍在执行,则意味着由于某种原因未正确捕获异常。我们需要弄清楚这一点!告诉我! 嘿,首先非常感谢您的详细回答。我已经尝试过了,它仍然没有被正确捕获。我也在 Stripe 上尝试过不同的错误。不管出现什么错误,什么情况,else 仍然会被执行 您能否完全按照问题部分中的方式分享您的最新代码?另外,您可以打印条带 API 生成的错误吗?打印这些信息:rescue Stripe::CardError => e # Since it's a decline, Stripe::CardError will be caught body = e.json_body err = body[:error] puts "Status is: #e.http_status" puts "Type is: #err[:type]" puts "Code is: #err[:code]" # param is '' in this case puts "Param is: #err[:param]" puts "Message is: #err[:message]" 并更新您的问题。 好的,我回家再看看。

以上是关于Ruby - 即使抛出了 Stripe 异常,else 块中的代码也会执行的主要内容,如果未能解决你的问题,请参考以下文章

Ruby实例编程说明字符编码,解决乱码问题

在 Ruby 中引发异常与抛出异常有啥区别?

测试 Flutter 中是不是抛出了特定的异常

bitmap.setPixel抛出了IllegalStateException 异常

symfony 在渲染模板的过程中抛出了异常

又抛出了一个异常:A RenderFlex 右边溢出了 3.0 像素