2015-01-09 93 views
2

我在客戶端有一個JavaScript代碼段,通過來自另一個Rails API應用程序的跨域請求數據。如何使用XMLHttpRequest對象發佈發佈請求?

var myData = { "event": {"name": "some event name", "property": "some value"} }; 
var request = new XMLHttpRequest(); 
request.open("POST", "http://localhost:3000/api/events", true); 
request.setRequestHeader('Content-Type', 'application/json'); 
request.send(JSON.stringify(myData)); 

不知爲什麼添加request.setRequestHeader( '內容 - 類型', '應用/ JSON');導致瀏覽器發送POST請求,但沒有此聲明,瀏覽器發送OPTIONS請求而不是?

此外,我得到了一個錯誤ActionController :: ParameterMissing - param丟失或值爲空:事件:在我的Rails應用程序運行上面的代碼時。爲什麼瀏覽器不發送myData變量中設置的數據?

版本信息:紅寶石2.1.5p273來說,Rails 4.1.8

# routes.rb 

Rails.application.routes.draw do 
    match '/api/events' => 'api/v1/events#create', via: :options 
    ... 
end 

# app/controller/api/v1/events_controller.rb 

class API::V1::EventsController < ApplicationController 
    skip_before_action :verify_authenticity_token 
    before_action :set_headers 

    def index 
    @events = Event.all 
    render json: @events, status: :ok 
    end 

    def show 
    @event = Event.find(params[:id]) 
    render json: @event 
    end 

    def create 
    @event = Event.new(event_params) 
    if @event.save 
     render json: @event, status: :created 
    else 
     render @event.errors, status: :unprocessable_entity 
    end 
    end 

    def update 
    @event = Event.find(params[:id]) 
    if @event.update(event_params) 
     raise "#{@event.name}" 
     head :no_content 
    else 
     render @event.errors, status: :unprocessable_entity 
    end 
    end 

    private 

    def event_params 
    params.require(:event).permit(:name, :property) 
    end 

    def set_headers 
    headers['Access-Control-Allow-Origin'] = '*' 
    headers['Access-Control-Expose-Headers'] = 'ETag' 
    headers['Access-Control-Allow-Methods'] = 'OPTIONS' #'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD' 
    headers['Access-Control-Allow-Headers'] = '*,x-requested-with,Content-Type,If-Modified-Since,If-None-Match' 
    headers['Access-Control-Max-Age'] = '1728000' 
    end 
end 

# Rails log 

Started OPTIONS "/api/events" for 127.0.0.1 at 2015-01-09 14:54:31 -0600 
    Processing by API::V1::EventsController#create as */* 
    Completed 400 Bad Request in 2ms 

    ActionController::ParameterMissing - param is missing or the value is empty: event: 
     actionpack (4.1.8) lib/action_controller/metal/strong_parameters.rb:187:in `require' 
     app/controllers/api/v1/events_controller.rb:39:in `event_params' 
     app/controllers/api/v1/events_controller.rb:18:in `create' 
     actionpack (4.1.8) lib/action_controller/metal/implicit_render.rb:4:in `send_action' 
     ... 

回答

3

瀏覽器發送OPTIONS請求給每個跨域的ajax post請求來檢查請求是否安全。要閱讀更多關於它搜索'cors'的信息。

解決您的問題刪除 'set_header' 的before_filter從控制器和

  1. 添加寶石 '機架CORS' 來的Gemfile
  2. 捆綁安裝以下到config/application.rb中
  • 添加
    config.middleware.insert_before 0, "Rack::Cors" do 
        allow do 
        origins '*' 
        resource '*', :headers => :any, :methods => [:get, :post, :options, :put, :head, :delete] 
        end 
    end 
    
  • +1

    你蘇使用機架寶石來充氣? – 2015-01-09 22:21:15

    +0

    是@SambathPrum,更新了答案。謝謝 – 2015-01-10 12:05:44

    1

    執行這個時候,因爲它是所有使用Rails默認情況下已經頁面我會使用jQuery。你可以做$.post('/api/events', myData)它會爲你處理一堆手動工作,並讓它在多個瀏覽器上工作。在附註中,您不需要需要key的引號括起來。

    1

    CORS需要針對非simple請求的預檢請求。預檢請求使用OPTIONS方法。未指定Content-Type的POST請求並不簡單,因爲不符合CORS的用戶代理通常不會提出這樣的請求。

    一個簡單的POST請求只能使用某些Content-Type值。粗略地說,這些對應於<form>元件可以發送的類型。 One of these(最近添加的)是application/json

    因此,如果您設置Content-Type: application/json,瀏覽器將不需要執行預檢請求。