Rails 4 - 只响应 JSON 而不是 HTML
Posted
技术标签:
【中文标题】Rails 4 - 只响应 JSON 而不是 HTML【英文标题】:Rails 4 - Respond only to JSON and not HTML 【发布时间】:2014-03-25 13:46:06 【问题描述】:我正在尝试在 rails 4 中构建 API,但在使用 respond_to :json
并尝试访问 html 版本时遇到了一个问题,即 rails 返回 500 错误而不是 406。
这是一个演示问题的示例控制器:
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
end
end
我还有一个 index
的 jbuilder 视图,它在通过 JSON 访问时有效。如果我尝试在没有 JSON 扩展的情况下访问路由,它会尝试加载 HTML 模板(不存在)并返回 500 错误,而不是仅渲染 JSON 或返回 406 错误。
这可能是什么原因造成的?为任何帮助干杯。
【问题讨论】:
可能重复:***.com/questions/14579774/… 我确实看到了,但我想知道为什么它不适用于respond_to :json
设置
respond_to :json
和 respond_with @posts
在生产中正确响应 HTTP/1.1 406 Not Acceptable 给我。在开发中,您会收到“HTTP/1.1 500 Internal Server Error”和ActionController::UnknownFormat
对不起,我试图回答,但我的帖子被版主删除了,因为我还回答了另一个“可能重复”,即使这个更清楚的是 Rails 4。所以你去......在 Rails 4,你必须在路由中传递一个 lambda 来强制执行这样的约束:resources :posts, constraints: lambda |req| req.format == :json
您可以在 Rails 指南的第二个注释中看到更多信息:edgeguides.rubyonrails.org/…
【参考方案1】:
我相信这里有两个部分: 1) json requests 在 rails 2) json 仅 responses 在 rails
1) 配置您的应用程序控制器以确保仅 json 请求
# app/controller/application_controller.rb
before_action :ensure_json_request
def ensure_json_request
return if request.format == :json
render :nothing => true, :status => 406
end
2) 配置您的 Rails API 路由以确保仅 json 响应
# config/routes.rb
MyApp::Application.routes.draw do
namespace :api, constraints: format: 'json' do
namespace :v1 do
resources :posts
end
end
end
【讨论】:
你可以使用request.format.symbol == :json
代替params[:format] == "json" || request.headers["Accept"] =~ /json/
。
很好的电话。用request.format == :json
更新,因为symbol
不需要其他request format question
你可以使用head :not_acceptable
而不是render :nothing => true, :status => 406
【参考方案2】:
为避免加载不存在的 HTML 模板,请在 config/routes.rb 中将默认资源类型设置为 JSON:
resources :posts, :defaults => :format => :json
【讨论】:
这不提供约束,这是问题所暗示的。这个想法是,如果没有指定 .json 格式,rails 将不会在路线上匹配并继续向下层级。【参考方案3】:在 Rails 4 中,您需要传递一个 lambda 来强制对路由进行约束。
不幸的是,这不起作用,因为它仍然会尝试提供(或尝试提供)html模板,因为格式是可选参数:
resources :posts, constraints: format: 'json'
这确实有效(使用 lambda):
resources :posts, constraints: lambda |req| req.format == :json
请参阅this section of the Rails guide 中的第二条(最后一条)注释。
【讨论】:
这似乎不适用于scope
,但defaults: format: 'json'
确实有效。【参考方案4】:
当您使用 before_filter 时,如果请求未定义的格式,您将收到 406 Not Acceptable。
例子:
class SomeController < ApplicationController
respond_to :json
def show
@record = Record.find params[:id]
respond_with @record
end
end
另一种方法是添加一个 before_filter 来检查格式并做出相应的反应。
例子:
class ApplicationController < ActionController::Base
before_filter :check_format
def check_format
render :nothing => true, :status => 406 unless params[:format] == 'json'
end
end
但我认为,你可以做到:
respond_to do |format|
format.json render :json => @posts
end
更多信息: http://guides.rubyonrails.org/layouts_and_rendering.html
【讨论】:
我遇到的问题是respond_to :json
仍然允许 html 响应通过。无论请求的格式如何,我都希望所有响应都是 JSON。
您是否在视图上创建了 json?
params[:format] == 'json'
还不够。当请求使用Accept: application/json
标头发出时,params[:format] 为空,但 Rails 仍以 JSON 响应。【参考方案5】:
constraints
不适用于 POST 请求,然后我尝试了 defaults
它适用于所有人。
namespace :api, :defaults => :format => 'json' do
namespace :v1 do
resources :users do
collection do
get 'profile'
end
end
post 'signup' => 'users#create'
post 'login' => 'user_sessions#create'
end
end
【讨论】:
【参考方案6】:你可以试试这个,因为我也遇到过这个问题,现在用这个解决方案解决了。
class PostsController < ApplicationController
respond_to :json
def index
@posts = Post.all
render json: @posts
end
end
【讨论】:
【参考方案7】:您可以通过使用将请求显式设置为 JSON 的前置过滤器来设置它。
request.format = :json
【讨论】:
【参考方案8】:当你在 json 中尝试响应是因为你只需要一些我使用的属性
@my_model=Model.select(:attributeN, :attributeN......, attributeN)
respond_to do |format|
format.json
render json: @my_model
end
【讨论】:
【参考方案9】:我建议你试试gem 'active_model_serializers'
。它真的很棒,而且很干净。
应用控制器:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception, if: Proc.new |c| c.request.format != 'application/json'
protect_from_forgery with: :null_session, if: Proc.new |c| c.request.format == 'application/json'
end
路线:
namespace :api, defaults: format: :json do
resource :posts
end
帖子控制器:
def index
render json: Post.all
end
【讨论】:
【参考方案10】:我有点晚了,但是关于你对this answer的评论:
我希望所有响应都是 JSON
最简单的解决方案是:
respond_to do |format|
format.all render :json => @posts
end
【讨论】:
以上是关于Rails 4 - 只响应 JSON 而不是 HTML的主要内容,如果未能解决你的问题,请参考以下文章
AFNetworking 将 text/html 读取为 html 而不是 JSON
为啥'javascript_pack_tag'只适用于'body'而不是html'head'(Rails 6和webpack)