需要在Rails中返回JSON格式的404错误

ibl*_*lue 76 ruby-on-rails

我在我的Rails应用程序中有一个普通的HTML前端和一个JSON API.现在,如果有人调用/api/not_existent_method.json它,则返回默认的HTML 404页面.有没有办法将此更改为类似于{"error": "not_found"}保留HTML前端的原始404页面完整的内容?

ibl*_*lue 111

一位朋友向我指出了一个优雅的解决方案,不仅可以处理404,还可以处理500个错误.实际上,它处理每个错误.关键是,每个错误都会产生一个异常,它会向上传播通过堆栈的机架中间件,直到由其中一个中间件处理.如果您有兴趣了解更多信息,可以观看这个精彩的截屏视频.Rails拥有自己的异常处理程序,但您可以通过记录较少的exceptions_app配置选项覆盖它们.现在,您可以编写自己的中间件,也可以将错误路由回rails,如下所示:

# In your config/application.rb
config.exceptions_app = self.routes
Run Code Online (Sandbox Code Playgroud)

然后你只需要匹配这些路线config/routes.rb:

get "/404" => "errors#not_found"
get "/500" => "errors#exception"
Run Code Online (Sandbox Code Playgroud)

然后你只需创建一个控制器来处理它.

class ErrorsController < ActionController::Base
  def not_found
    if env["REQUEST_PATH"] =~ /^\/api/
      render :json => {:error => "not-found"}.to_json, :status => 404
    else
      render :text => "404 Not found", :status => 404 # You can render your own template here
    end
  end

  def exception
    if env["REQUEST_PATH"] =~ /^\/api/
      render :json => {:error => "internal-server-error"}.to_json, :status => 500
    else
      render :text => "500 Internal Server Error", :status => 500 # You can render your own template here
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

最后要添加的内容:在开发环境中,rails通常不会呈现404或500页,而是打印回溯.如果要ErrorsController在开发模式下查看您的操作,请禁用config/enviroments/development.rb文件中的回溯内容.

config.consider_all_requests_local = false
Run Code Online (Sandbox Code Playgroud)

  • 另外,不要忘记将状态代码添加到渲染中.否则,您的客户端/浏览器将不知道它是404/500.render:text =>"404 not found",:status =>:not_found (4认同)
  • 在使用上面提出的解决方案之前,请查看此答案:http://stackoverflow.com/a/29292738/2859525.只需在祖先控制器中捕获404并使用回调来进行简单的JSON错误响应就更简单了. (2认同)

Gre*_*sov 13

我想创建一个单独的API控制器来设置格式(json)和api特定的方法:

class ApiController < ApplicationController
  respond_to :json

  rescue_from ActiveRecord::RecordNotFound, with: :not_found
  # Use Mongoid::Errors::DocumentNotFound with mongoid

  def not_found
    respond_with '{"error": "not_found"}', status: :not_found
  end
end
Run Code Online (Sandbox Code Playgroud)

RSpec测试:

  it 'should return 404' do
    get "/api/route/specific/to/your/app/", format: :json
    expect(response.status).to eq(404)
  end
Run Code Online (Sandbox Code Playgroud)

  • 这似乎只适用于记录。您将如何管理“api/non_existant_route”的案例? (3认同)

bio*_*net 11

当然,它看起来像这样:

class ApplicationController < ActionController::Base
  rescue_from NotFoundException, :with => :not_found
  ...

  def not_found
    respond_to do |format|
      format.html { render :file => File.join(Rails.root, 'public', '404.html') }
      format.json { render :text => '{"error": "not_found"}' }
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

NotFoundException不是异常的真实姓名.它将随Rails版本和您想要的确切行为而变化.通过Google搜索很容易找到.

  • 感谢您的想法,但我正在使用Rails 3.2.2,其中异常处理已更改.这将不再有效. (2认同)

jdo*_*doe 5

尝试放在你的末尾routes.rb

match '*foo', :format => true, :constraints => {:format => :json}, :to => lambda {|env| [404, {}, ['{"error": "not_found"}']] }
Run Code Online (Sandbox Code Playgroud)