Ruby-on-rails 需要在 Rails 中返回 JSON 格式的 404 错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10253366/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Need to return JSON-formatted 404 error in Rails
提问by iblue
I am having a normal HTML frontend and a JSON API in my Rails App. Now, if someone calls /api/not_existent_method.jsonit returns the default HTML 404 page. Is there any way to change this to something like {"error": "not_found"}while leaving the original 404 page for the HTML frontend intact?
我的 Rails 应用程序中有一个普通的 HTML 前端和一个 JSON API。现在,如果有人调用/api/not_existent_method.json它会返回默认的 HTML 404 页面。有什么方法可以将其更改为{"error": "not_found"}同时保留 HTML 前端的原始 404 页面完整无缺?
回答by iblue
A friend pointed me towards a elegant solution that does not only handle 404 but also 500 errors. In fact, it handles every error. The key is, that every error generates an exception that propagates upwards through the stack of rack middlewares until it is handled by one of them. If you are interested in learning more, you can watch this excellent screencast. Rails has it own handlers for exceptions, but you can override them by the less documented exceptions_appconfig option. Now, you can write your own middleware or you can route the error back into rails, like this:
一位朋友向我指出了一个优雅的解决方案,它不仅可以处理 404 错误,还可以处理 500 错误。事实上,它处理每一个错误。关键是,每个错误都会生成一个异常,该异常通过机架中间件堆栈向上传播,直到被其中一个处理。如果您有兴趣了解更多信息,可以观看这个精彩的截屏视频。Rails 有自己的异常处理程序,但您可以通过文档较少的exceptions_app配置选项覆盖它们。现在,您可以编写自己的中间件,也可以将错误路由回 rails,如下所示:
# In your config/application.rb
config.exceptions_app = self.routes
Then you just have to match these routes in your config/routes.rb:
然后你只需要在你的config/routes.rb:
get "/404" => "errors#not_found"
get "/500" => "errors#exception"
And then you just create a controller for handling this.
然后你只需创建一个控制器来处理这个问题。
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
One last thing to add: In the development environment, rails usally does not render the 404 or 500 pages but prints a backtrace instead. If you want to see your ErrorsControllerin action in development mode, then disable the backtrace stuff in your config/enviroments/development.rbfile.
最后要补充的一点是:在开发环境中,rails 通常不渲染 404 或 500 页,而是打印回溯。如果您想ErrorsController在开发模式下查看您的操作,请禁用config/enviroments/development.rb文件中的回溯内容。
config.consider_all_requests_local = false
回答by Greg Funtusov
I like to create a separate API controller that sets the format (json) and api-specific methods:
我喜欢创建一个单独的 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
RSpec test:
RSpec 测试:
it 'should return 404' do
get "/api/route/specific/to/your/app/", format: :json
expect(response.status).to eq(404)
end
回答by bioneuralnet
Sure, it will look something like this:
当然,它看起来像这样:
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
NotFoundExceptionis notthe real name of the exception. It will vary with the Rails version and the exact behavior you want. Pretty easy to find with a Google search.
NotFoundException是不是异常的真实姓名。它会因 Rails 版本和您想要的确切行为而异。用谷歌搜索很容易找到。
回答by jdoe
Try to put at the endof your routes.rb:
尝试放在你的末尾routes.rb:
match '*foo', :format => true, :constraints => {:format => :json}, :to => lambda {|env| [404, {}, ['{"error": "not_found"}']] }

