読者です 読者をやめる 読者になる 読者になる

うめすこんぶ

日々のプログラミングで残しておきたいメモ.何かの役に立てれば幸いです.

No 'Access-Control-Allow-Origin' を理解する

web rails

RailsでS3に上げたフォントを読み込もうとするとき、 No 'Access-Control-Allow-Origin' のエラーがでた。

以前、jqueryでxhr(XML HTTP Request)をやろうとした時にもでた覚えがある。正直その時は何がなんだかと言う感じだったが、再びであったのできちんと理解したい。

No 'Access-Control-Allow-Origin'

正確なエラーは此れ。

Font from origin 'http://s3xxxxxx' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://xxx.com' is therefore not allowed access.

ある場所から、s3へのアクセスが禁止されているとのこと。オリジンというのは、ドメインと似ている言葉だけど、正確にはプロトコル(httpなど) + ドメイン + ポート番号がオリジン。要はhttp://example.com:80/index.htmlの80までがオリジン。Unixでいうhomeディレクトリ(~で表す)のイメージだと思うと理解しやすいかも。いわゆる、自分の居場所。ただ、基本ドメインと似た意味と思っても問題なさそう。

この問題がでる場面は、Mozillaのページに書いてある。HTML5からの仕様とのことだ。あるオリジンと紐付いたプログラムが別のオリジンへのアクセスを行うとき起こるが、HTMLやCSSに記述する画像ファイルやスクリプトの読み取りなどでは発生しない。すべてではないが、例えば以下条件下で発生する。

  • Xml HTTP Requestを利用したアクセス(javascriptでよく書いたりする)
  • Webフォントを引っ張ってくるときなどでも出る。

Access-Control-Allow-Originは、アクセス許可されたオリジンと言う意味で、セキュリティ上情報漏洩を防ぐとか改ざんを防ぐため用いる。ファイアウォールやファイルパーミッションに似ている。

対処方法

セキュリティ上設定する必要はあるけど、プログラムを作るとき、このせいでうまくアクセスできないで止まることが多い。対処としては、それぞれのサーバのCORS設定を変える。CORS(Cross-origin resource sharing)とは、別々のドメイン間でアクセス許可する仕組み。パーミッション設定に近い。

サーバーサイドでの設定方法だが、Access-Control-Allow-Originヘッダにアクセス許可するクライアントのドメインを指定する。面倒なら「*」(ワイルドカード)で指定すればいい。直接httpヘッダを変えてもいいけど、サーバサイドフレームワークやアプリケーション側で設定するほうが簡単。

phpのサーバサイドプログラムなら、

$allowed_origin = 'http://service.example.com';

とするし、

例えば、S3なら、以下ページを参考にアクセス許可の設定ができる。やってることは、AWSコンソールでCORSファイルの編集をするだけだ。

Access-Control-Allow-Originの罠! Amazon S3にあるファイルをAjaxでアクセスしようとしたら激ハマリした話 - nigoblog

RAILSなどのフレームワークなら、config/application.rbのようにアプリケーション全般の設定が書かれたファイルで設定を書けばいい。

ローカルファイルからのxhr

また、chromeでローカルファイル上でxhrを使用して、モックサーバ(rails sとか)のファイルへアクセスしようとするときもこのエラーに見舞われる。

以下ページに対処が書かれている。解説もあるのでわかりやすい。

【解説付き】chromeでXMLHttpRequestをローカルのファイルで行う方法 - Qiita

MacPortからHomebrewへの移行方法

mac

以下ページに従ってmacportをOSX10.10.5で使えるようにする。 そもそも、macportだけをアンインストールしようとしても、以下エラーでできない。

Error: Current platform "darwin 14" does not match expected platform "darwin 13" Error: If you upgraded your OS, please follow the migration instructions: https://trac.macports.org/wiki/Migration OS platform mismatch while executing "mportinit ui_options global_options global_variations"

そこで、回り道になるが、macportをOSに合わせたものをインストールしてきて、 それをアンインストールするという手順を踏むことにする。 手順は以下。

  1. Xcodeを再インストール
  2. MacPortsを再インストール
  3. MacPortsでインストールしていたものを書き出して,一度全て消去.書き出したリストを使ってもう一度インストール

1. xcodeのインストール

インストールはせず、以下コマンド叩くだけ。

sudo xcode-select --install
sudo xcodebuild -license

2.「MacPortをインストール」

https://www.macports.org/install.php

このページからOSに該当するもの持ってきてダウンロード&インストール。

3.

※ 3.はもしかしたらこの手順すべてはいらないかもしれません。一応Migrationの手順に沿ってます。

port -qv installed > ports.list

とかでインストールしていたものを書き出し、

sudo port -f uninstall installed
sudo port clean all

で一度全て削除。

以下、スクリプトを持ってきて再インストール。

curl -0 https://svn.macports.org/repository/macports/contrib/restore_ports.tcl
chmod +x restore_ports.tcl
sudo ./restore_ports.tcl ports.list

アンインストール

次に、アンインストールする。

$ sudo port -fp uninstall --follow-dependents installed

残りの設定ファイル等を削除する。

sudo rm -rf \
  /opt/local \
  /Applications/DarwinPorts \
  /Applications/MacPorts \
  /Library/LaunchDaemons/org.macports.* \
  /Library/Receipts/DarwinPorts*.pkg \
  /Library/Receipts/MacPorts*.pkg \
  /Library/StartupItems/DarwinPortsStartup \
  /Library/Tcl/darwinports1.0 \
  /Library/Tcl/macports1.0 \
  ~/.macports

~/.bash_profileからMacPortsインストール時に追加した以下のPATHを削除。

export PATH=/opt/local/bin:/opt/local/sbin:$PATH

Homebrewのインストール

/usr/bin/ruby -e "$(/usr/bin/curl -fksSL https://raw.github.com/mxcl/homebrew/master/Library/Contributions/install_homebrew.rb)"

これにて完了。

参考文献