Access-Control-Allow-Origin と Access-Control-Allow-Headers について
Slim3 で JSON を受け取るために、久しぶりに Ajax のデータを受け取る処理を記述していたら、(Chrome 上で)下記のエラーが発生した。
XMLHttpRequest cannot load http://localhost:8888/api/json/... Origin http://localhost is not allowed by Access-Control-Allow-Origin.
Access-Control-Allow-Origin
調べてみたところ、サーバーからのレスポンスに、
Access-Control-Allow-Origin: *
の HTTP ヘッダを追加する必要があるようだ。仮に Slim3 で記述をするとしたら、Controller にこう書く。
public class LatestController extends Controller { private PostService service = new PostService(); @Override public Navigation run() throws Exception { String json = service.getLatestPostIn10AsJson(); requestScope("json", json); response.setHeader("Access-Control-Allow-Origin", "*"); return forward("latest.jsp"); }
この「Access-Control-Allow-Origin」の値には、特定のドメイン名を記述して利用制限をしてもよい。*1
Access-Control-Allow-Headers
上記の設定だけで、jQuery は動いた。今度は ExtJS で Ajax を使ってみようとしたら、今度は、
XMLHttpRequest cannot load http://localhost:8888/api/json/.... Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers.
調べてみたら、ExtJS が Ajax のリクエストをする際に、ヘッダに
X-Requested-With: XMLHttpRequest
を送っていることが原因らしい。このリクエストヘッダが送信された場合には、レスポンスヘッダ
Access-Control-Allow-Headers: X-Requested-With
を返す必要がある。*2
そのため、このヘッダを返すように設定を追加して、エラーが発生しないことをやっと確認した。
@Override public Navigation run() throws Exception { String json = service.getLatestPostIn10AsJson(); requestScope("json", json); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Headers", "X-Requested-With"); return forward("latest.jsp"); }
サーバが返すレスポンスヘッダ
例
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Access-Control-Allow-Origin: * Access-Control-Allow-Headers: X-Requested-With Content-Length: 328909876 Server: Jetty(6.1.x)
*1:ただし、ブラウザがエラーを返すから書いているだけで、この記述を無視する Ajax クライアントを実行させることは可能である
*2:prototype.js も同様に上記のヘッダを追加するようだ