在Rails中的异常之后存储响应HTTP状态代码

时间:2016-06-15 15:41:35

标签: ruby-on-rails rest

我正在使用Ruby on Rails开发REST Web服务。

在每个请求之后,我想在数据库中存储响应HTTP状态代码,即使存在一些异常。我怎么能这样做?

我做了这两次尝试都没有成功:

  • 应用程序控制器中的after_filter

    class Api::ApiController < ActionController::Base
        before_action :set_current_rest_request
        after_filter :finalize_current_rest_request
        private
        def set_current_rest_request
            @current_rest_request = RestRequest.new
            @current_rest_request.request_at = DateTime.now
            @current_rest_request.save
        end
        def finalize_current_rest_request
            @current_rest_request.answer_at = DateTime.now
            @current_rest_request.http_status_code = response.status
            @current_rest_request.save
        end
    end
    

    不起作用,因为在异常的情况下不会调用finalize_current_rest_request

  • 应用程序控制器中的rescue_from

    class Api::ApiController < ActionController::Base
        before_action :set_current_rest_request
        after_filter :finalize_current_rest_request
        rescue_from Exception, :with => :handle_exception
        private
        def set_current_rest_request
            @current_rest_request = RestRequest.new
            @current_rest_request.request_at = DateTime.now
            @current_rest_request.save
        end
        def finalize_current_rest_request
            @current_rest_request.answer_at = DateTime.now
            @current_rest_request.http_status_code = response.status
            @current_rest_request.save
        end
        def handle_exception(exception)
            finalize_current_rest_request
            raise exception
        end
    end
    

    因为在异常引发之前我在handle_exception中调用finalize_current_rest_request

  • 时,response.status仍然是200,所以不起作用

2 个答案:

答案 0 :(得分:0)

您需要使用开始救援块来包装控制器的每个操作。类似的东西:

begin
  respond_to do |format|
    format.json { redirect_to foos_path, notice: 'Foo was successfully destroyed.' }
rescue 
  @current_rest_request.http_status_code = response.status
  end
end

通常这样的行为留给了日志,但我假设你有充分的理由这样做。

如果你真的希望它如你所提到的那样干,你可以放入你的应用程序控制器:

rescue_from Exception, :with => :store_request

def store_request
  current_rest_request = RestRequest.new
  current_rest_request.request_at = DateTime.now
  current_rest_request.http_status_code = response.status
  current_rest_request.save
end

注意:在应用程序控制器中进行全面救援通常被认为是不好的做法。我认为实际处理此问题的最佳方法是实施全面的日志记录方案。

答案 1 :(得分:0)

我终于解决了添加中间件的问题(here一些有关Rails中间件如何工作的数据)。 详细地,在config / application.rb中,我添加了:

config.middleware.insert_before "Rails::Rack::Logger","StoreStatus"

api控制器是

class Api::ApiController < ActionController::Base
    before_action :set_current_rest_request
    private
    def set_current_rest_request
      @current_rest_request = RestRequest.new
      request.env[:current_rest_request] = @current_rest_request
    end
end

我添加了带有以下代码的文件lib / store_status.rb:

class StoreStatus
  def initialize(app)
    @app = app
  end

  def call(env)
    data = @app.call(env)
    if (env[:current_rest_request])
      rest_request = env[:current_rest_request]
      rest_request.http_status_code = data[0]
      rest_request.save
    end
    data
  end
end

请注意,可能会出现一些语法错误,因为已获得该代码,从而重构了包含此问题其他无用的复杂性的代码。