Redmineが好き過ぎてRedmineを題材にしたファンタジー小説書いてる8amjpです。
Redmine API
さて、Redmineは素晴らしいツールなんですが、画面がちょっと無機質で、初心者には取っ付きにくい……という印象があります。
そこで私は、もう少し取っ付きやすい画面を提供するため、Angularを使ってRedmine API経由でチケットの情報にアクセスするWebクライアントアプリを作ろうと考えました。
このRedmine API、とっても便利なんですよ。AngularのHTTPモジュールからGETメソッドでアクセスすれば、チケットの情報をJSONやXMLの形式で自由自在に取得できます。
さらには、POSTメソッドやPUTメソッドを使えば、チケットの作成や更新も簡単に……
……できないんですよ。
Redmine APIに、Chrome等のWebブラウザからPOST/PUTメソッドでリクエストを送信すると、必ずエラーになります。
えー。これじゃ読み取り専用じゃないですか。なんで?
なぜエラーになるのか
勉強してみましたよ。もう。
えーと、Redmine APIにアクセスする時など、別ドメインへのリクエストは、セキュリティ上の理由で厳しいルールが課せられます。
そのルールを規定したのがCross-Origin Resource Sharing、略してCORSと呼ばれるものです。
で、「シンプルではない」リクエスト(PUT等)の送信時は、安全性を確認するため、事前にOPTIONSメソッドでリクエストを送信し、正常な応答があれば続けてPUTメソッドを送信します。
これをプリフライトリクエストといって…………
と、頭の痛くなるような(でもセキュリティ上とても大事な)ルールに縛られながら、リクエストを送るわけなんですが。ここで大問題が発生です。
まず、ChromeやFirefoxといった主要なWebブラウザは、必ずプリフライトリクエストを送信します。仕様です。簡単にはオフにできません。
で、Redmine APIでは、このプリフライトリクエストに応答する術がありません。必ず404エラーを返します。
結果、POSTもPUTもできません。
どうせえっちゅうんだよーー!!
インターネットに公開されたサーバーでならわかるけどよー! イントラの内部でくらい自由にやらせてくれよーー!!
畜生めー!! ちくしょうめーーー!!!
解決方法
というわけで、Apacheにこの怒りをぶつけてやりましょう。
/apps/redmine/conf/
ディレクトリにあるhttpd-app.conf
の末尾に、下記を追記します。
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "OPTIONS, PUT"
Header always set Access-Control-Max-Age "60"
Header always set Access-Control-Allow-Headers "Content-Type, X-Redmine-API-Key"
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
これでPOSTもPUTも送信し放題。いやー、嬉しくて何度POST/PUTしたことやら。
詳しいことはさっきのMDNのページに書いてありますが、一応さらりと解説しておきますね。
1行目は、どのドメインからのアクセスを許可するかを指定します。
ワイルドカードを指定すればすべてのアクセスを受け付けますが、セキュリティの事を考えるとちゃんと指定すべきです。わかっちゃいるけど。
2行目は、どのメソッドを許可するかを指定します。GET/HEAD/POSTメソッドは既に許可されてるっぽいので、OPTIONSとPUTメソッドを追加で指定します。
3行目は、プリフライトリクエストの有効期間です。とりあえず60秒にしました。深い根拠はありません。
4行目は、どのリクエストヘッダを許可するかを指定します。Redmine APIでは「Content-Type」と「X-Redmine-API-Key」ヘッダは必須なので、それを指定しています。
5-7行目は、OPTIONSメソッドのリクエストがあったらオウム返しにステータスコード200を返します。ゆるゆる門番。
これで、長らく頭を悩ませていた問題が、力技とは言えやっと解決になりました。良かった良かった。
ま、解決できたのは、本家Redmineサイトのフォーラム内のこの記事のおかげなんですけどね。ありがとうございます。
おわりに
「わざわざこんな事しなくても、こうすれば簡単にPOST/PUTできるよー」などという情報を御存知でしたらぜひ教えてください。