簡體   English   中英

Rails 4 - 僅響應 JSON 而不是 HTML

[英]Rails 4 - Respond only to JSON and not HTML

我正在嘗試在 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 錯誤。

什么可能導致這種情況? 為任何幫助干杯。

我相信這里有兩部分:
1) json 只在 rails 中請求
2) json 僅在 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  

為避免加載不存在的 HTML 模板,請在 config/routes.rb 中將默認資源類型設置為 JSON:

resources :posts, :defaults => { :format => :json }

在 Rails 4 中,您需要傳遞一個 lambda 來對路由實施約束。

不幸的是,這將不起作用,因為它仍然會嘗試提供(或嘗試提供)一個 html 模板,因為格式是一個可選參數:

resources :posts, constraints: { format: 'json' }

這確實有效(使用 lambda):

resources :posts, constraints: lambda { |req| req.format == :json }

請參閱Rails 指南本部分中的第二個(最后)注釋。

當您使用 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

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

你可以試試這個,因為我也遇到了這個問題,現在使用這個解決方案解決了。

class PostsController < ApplicationController
  respond_to :json

  def index
    @posts = Post.all
    render json: @posts
  end
end

您可以通過使用 before 過濾器將請求顯式設置為 JSON 來設置它。

request.format = :json

當您在 json 中嘗試響應時,因為您只需要一些我使用過的屬性

@my_model=Model.select(:attributeN, :attributeN......, attributeN)
respond_to do |format|
  format.json {
    render json: @my_model
  }
end

我建議您嘗試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

我對此有點晚了,但關於您對此答案的評論:

我希望所有響應都是 JSON

最簡單的解決方案是:

respond_to do |format|
  format.all { render :json => @posts }
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM