我正在努力让CORS在我的JSON api Rails应用程序中正常工作。
我有一个Event
模型和相关的控制器。 Event
属于RegisteredApplication
s。
# Routes.rb
Rails.application.routes.draw do
root 'registered_applications#index'
resources :registered_applications
namespace :api, defaults: { format: :json } do
# OPTION is an HTTP verb
match '/events', to: 'events#create', via: [:options]
resources :events, only: [:create]
end
devise_for :users
end
# events_controller.rb
class API::EventsController < ApplicationController
skip_before_filter :verify_authenticity_token
before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
# If this is a preflight OPTIONS request, then short-circuit the request,
# return only the necessary headers and return an empty text/plain.
def cors_preflight_check
if request.method == :options
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
headers['Access-Control-Allow-Headers'] = 'X-Requested-With, X-Prototype-Version'
headers['Access-Control-Max-Age'] = '1728000'
render :text => '', :content_type => 'text/plain'
end
end
# For all responses in this controller, return the CORS access control headers.
def cors_set_access_control_headers
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
headers['Access-Control-Max-Age'] = "1728000"
end
def create
registered_application = RegisteredApplication.find_by(url: request.env['HTTP_ORIGIN'])
if registered_application.nil?
render json: "Unregistered application", status: :unprocessable_entity
else
event = registered_application.events.new(event_params)
if event.save
render json: @event, status: :created
else
render @event.errors, status: :unprocessable_entity
end
end
end
private
def event_params
params.permit(:name)
end
end
我用来将新点击事件发送到我的Rails应用程序的JavaScript:
$( document ).ready(function() {
$( window ).click( function() {
metrics.report("click");
});
});
var metrics = {};
metrics.report = function(eventName) {
var event = { name: eventName };
var request = new XMLHttpRequest();
request.open("POST", "http://localhost:3000/api/events", true);
request.setRequestHeader('Content-Type', 'application/json');
request.send(JSON.stringify(event));
}
有两个问题:
1)当我通过上述javascript(来自其他网页)发出请求时,我收到XMLHttpRequest cannot load http://localhost:3000/api/events. Request header field Content-Type is not allowed by Access-Control-Allow-Headers
错误。我的Rails api要求请求是JSON,所以我不知道我应该怎么做。如果我注释掉setRequestHeader()
行,则错误消失,但我的Rails应用程序未收到初始HTTP OPTIONS
请求。
2)在Rails应用程序端,我看到OPTIONS请求,但第二个(POST)请求永远不会发生。这是我日志中的唯一内容:
Started OPTIONS "/api/events" for ::1 at 2015-08-30 12:54:17 -0400
Processing by API::EventsController#create as JSON
RegisteredApplication Load (0.2ms) SELECT "registered_applications".* FROM "registered_applications" WHERE "registered_applications"."url" = $1 ORDER BY created_at DESC LIMIT 1 [["url", "http://localhost:2222"]]
Unpermitted parameter: format
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "events" ("registered_application_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["registered_application_id", 21], ["created_at", "2015-08-30 16:54:17.751257"], ["updated_at", "2015-08-30 16:54:17.751257"]] (0.4ms) COMMIT
Completed 201 Created in 11ms (Views: 0.1ms | ActiveRecord: 1.1ms)
我错过了一些明显的东西吗?
答案 0 :(得分:2)
我认为您需要在服务器端代码的headers['Access-Control-Allow-Headers'] = "Content-Type"
函数中添加cors_set_access_control_headers
。
My Rails api要求请求是JSON,所以我不知道我应该怎么做。如果我注释掉
setRequestHeader()
行,那么错误就会消失,但是我的Rails应用程序没有收到初始的HTTP OPTIONS请求。
根据CORS规范,如果您发送的Content-Type
请求标头的值不是application/x-www-form-urlencoded
,multipart/form-data
或text/plain
,那么CORS预检{ {1}}请求已发送。
因此,当您发送带有OPTIONS
值的Content-Type
标头时,它会触发application/json
请求。但是当您删除OPTIONS
行时,则不会发送自定义setRequestHeader()
标头(并且没有其他自定义“作者”标头),因此在这种情况下,不需要CORS预检,因此不会{{1请求已经完成。