CORS (Cross-Origin Resource Sharing)
http://dev.classmethod.jp/cloud/cors-cross-origin-resource-sharing-cross-domain/
CORS(Cross-Origin Resource Sharing)は、その名の通り、ブラウザがオリジン(HTMLを読み込んだサーバのこと)以外のサーバからデータを取得する仕組みです
JSONPという仕組みを使ってできちゃう。抜け道的なやり方で使われていました
S3でCORSの設定ができるようになった
S3でCORSの設定ができるようになって嬉しいことは何でしょうか。例えば、オリジンWebサイトがEC2で動いていたとします。読み込んだHTML内のJavaScriptでは、動的にパラメータを読み込んでいます。CORS設定が無い場合には、EC2を経由してブラウザに返していたりJSONPを使っていましたが、CORS設定があれば、JavaScript内のAjax通信でクロスドメインのS3から情報をダイレクトに取得できます。 逆に、S3をオリジンWebサイトとして運用している場合は、EC2側でCORS設定を行う事で、S3とEC2のドメインが異なっていたとしてもAjax内で呼び出しができるようになります。今まで、S3を起点としたWebページの場合、EC2の動的プログラムを呼び出すにはJSONPを使った方法しか無かったのですが、普通のJSON呼び出しをはじめ、JSP/PHP/Ruby/Python/ASP等を呼び出せるようになりました。さらに、S3はキャッシュサーバとしてCloudFrontのオリジンとしても動きますので、トップページをCloudFrontにして静的コンテンツは全てここから配信し、動的コンテンツをCORSを使って呼び出す事が出来て、各サーバの役割分担がより明確になります。
S3は基本ストレージサービスだが、最近は静的WEBページを運用するにも使われる
S3でCORSの設定
Bucket > Add CORS Configuration
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>
他
#
OPTIONS methodについて http://stackoverflow.com/questions/12320467/jquery-cors-content-type-options
- This OPTIONS request is the CORS preflight request.
- It is a request that is sent to the server before the actual request in order to ask permissions to make the request
The custom Content-Type is in fact triggering the preflight. According to the CORS spec (http://www.w3.org/TR/cors/), any Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain triggers the preflight.
If you have no control over the remote server, then you'll need to either ask them to support CORS preflight, or try some other option such as JSON-P.
If you do have control over the remote server, you can change it to handle preflights. In order to handle a preflight request, you should send the following headers in the response to the OPTIONS request:
Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST Access-Control-Allow-Headers: Content-Type The response should be an HTTP 200. The Access-Control-Allow-Methods response header can either echo the value of the Access-Control-Request-Method, or it can just be GET, POST, PUT, DELETE to support all methods. The Access-Control-Allow-Headers response header should echo the values in the Access-Control-Request-Headers request header.
Once the browser receives those headers, it will make the actual request. You can learn more about CORS preflight requests here:
http://www.html5rocks.com/en/tutorials/cors/
http://stackoverflow.com/questions/20087584/jquery-and-rails-ajax-request-and-response
CORSを解決してもjson parameterをparseする部分でエラーがでる場合
JSON.stringifyを利用
https://developer.mozilla.org/ja/docs/JavaScript/Reference/Global_Objects/JSON/stringify
data : JSON.stringify({name:"ravi",age:"31"}),
jqueryを利用したajax post sample
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script>
function doCors(){
$.ajax({
type: "post",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({ "items": [{ "code": "test1" , "name": "aaa"},{ "code": "test2" , "name": "bbb" }]}),
url : "https://your_api/xxx.json",
success : function( json ){
$("#msg").append("success : "+json.success+" : "+json.xxxx + "<br>");
},
error : function (xhr,text,thrown){
$("#msg").text("error : "+text);
}
});
}
</script>
</head>
<body>
<input type="button" value="CORS Test" onclick="doCors()"><br>
<p id="msg"></p>
</body>
</html>
rails CORS header
http://www.tsheffler.com/blog/?p=428
CORSのリクエスト順番とOPTION method
たとえ以下のようなjson requestがあったとしよう
GET http://othersite.com/method.json
このリクエストが送られる前にブラウザは以下のようなリクエストを先に送る
OPTIONS http://othersite.com/method.json
Origin: http://mysite.com
Access-Control-Request-Method: GET
その後、サーバは以下のようにresponse
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Max-Age: 1728000
Content-Length: 0
Content-Type: text/plain
次にもともとをrequestを送る
GET http://othersite.com/method.json
このOPTION methodを対応するには?
OPTIONS requestに対するresponseを返す必要がある
rails
before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
# For all responses in this controller, return the CORS access control headers.
# ここは元のrequestのため
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
# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.
# ここはOPTIONS method requestのresponseのため
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
rails gem
railsのgemを利用する場合
gem 'rack-cors', :require => 'rack/cors'
rackレベルでヘッダを処理してくれる
application.rb
module YourApp
class Application < Rails::Application
...
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '*', :headers => :any, :methods => [:get, :post, :options]
end
end
...
end
end
nginx
# CORS対応
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Content-Type,Accept';
add_header 'Access-Control-Allow-Method' 'GET, POST, OPTIONS, PUT';
# 条件付き
if ($http_origin ~ "^(http://developers.example.com|http://example.com)$") {
add_header "Access-Control-Allow-Origin" $http_origin;
}