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

我有一个正常的HTML前端和JSON API在我的Rails应用程序。 现在,如果有人调用/api/not_existent_method.json它将返回默认的HTML 404页面。 有没有什么办法可以把这个改成像{"error": "not_found"}同时保持HTML前端原来的404页面不变?

一位朋友指出,我不仅可以处理404错误,而且还可以处理500个错误。 事实上,它处理每一个错误。 关键是,每个错误都会产生一个exception,通过一堆机架中间件向上传播,直到其中的一个被处理。 如果你有兴趣学习更多,你可以观看这个优秀的截屏 。 Rails有它自己的exception处理程序,但是你可以用更less的logging的exceptions_appconfiguration选项覆盖它们。 现在,你可以编写你自己的中间件,或者你可以把错误发回到rails中,就像这样:

 # In your config/application.rb config.exceptions_app = self.routes 

那么你只需要在config/routes.rb匹配这些路由:

 get "/404" => "errors#not_found" get "/500" => "errors#exception" 

然后你只是创build一个控制器来处理这个。

 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 

最后要补充的是:在开发环境中,rails通常不会呈现404或500页面,而是会打印回溯。 如果你想在开发模式下看到你的ErrorsController在运行,那么在你的config/enviroments/development.rb文件中禁用backtrace。

 config.consider_all_requests_local = false 

我喜欢创build一个单独的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 

RSpectesting:

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

当然,它会看起来像这样:

 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 

NotFoundException 不是exception的真实名称。 它将随着Rails版本和你想要的确切行为而变化。 很容易find一个谷歌search。

尝试把你的routes.rb 结束

 match '*foo', :format => true, :constraints => {:format => :json}, :to => lambda {|env| [404, {}, ['{"error": "not_found"}']] }