Ajaxでリクエストを飛ばした時に、No 'Access-Control-Allow-Origin'エラーが出ないようにSpring MVC側でフィルタをかける


スポンサーリンク

jQueryから$.ajaxでリクエストを投げると、

Uncaught TypeError: undefined is not a function gallery.js:2
XMLHttpRequest cannot load http://localhost:8080/shiori/img_list. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

なんて出ることがあります。

これは、XMLHttpRequestを投げるときは、Request元のドメインとRequest先のドメインとが一致する必要があったからです。
localhost:80からlocalhost:8080にリクエストを投げても、ドメインが一致していないとされてSame Origin Policyエラーが出ます。

その辺は、dankogaiさんの
Ajax - Goodbye, JSONP. Hello, Access-Control-Allow-Origin
が詳しいです。

これの対策方法は、上記のブログで

Access-Control-Allow-Originヘッダーにアクセス元のドメインが入っているか、*でワイルドカード指定されているかすれば、Same Origin Policy は適用されないよ、

と書かれているように、レスポンスヘッダーに"Access-Control-Allow-Origin", "*"を追加すればいいということです。

そのためには、サーブレットのFilter機能を使います。
サーブレットフィルタとは、サーブレットが呼び出される前にブラウザから送信された情報を加工するためのJavaの機能です。
リクエストやレスポンスにフィルタをかけて、ヘッダに*(全てのリクエストの)Access-Controle-Allow-Origin(許可する)というフィルタをかければいいわけです。

以下のサイトを参考に、フィルタを作ってみました。
Enabling Cross Origin Requests for a RESTful Web Service

shiori.filter.FilterService.java

package shiori.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class FilterService implements Filter {
	private String encoding = null;
	
	public void init(FilterConfig config) throws ServletException {
		encoding = config.getInitParameter("encoding");
	}
	
	public void doFilter(ServletRequest req, ServletResponse res,
						FilterChain chain) throws ServletException, IOException {
		//文字コード設定
		req.setCharacterEncoding(encoding);
		HttpServletResponse response = (HttpServletResponse) res;
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
		response.setHeader("Access-Control-Max-Age", "3600");
		response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
		chain.doFilter(req, res);
	}
	
	public void destroy() {
		encoding = null;
	}
}

このFilterServiceをweb.xmlに定義します。

web.xml

<!-- filter -->
<filter>
  <filter-name>Encoding</filter-name>
  <filter-class>shiori.filter.FilterService</filter-class>
  <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>

</filter>
<filter-mapping>
  <filter-name>Encoding</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

これだけで、クロスドメインでのリクエストが可能になりました。


作ればわかる!Google App Engine for Javaプログラミング

作ればわかる!Google App Engine for Javaプログラミング

filterの書き方はこの本を参考にしました!
ありがとうございます!
隠れた名著です(笑)