「Access-Control-Allow-Origin」ヘッダの設定で、異なるドメインからのajax呼び出しを行う(Servlet,Apache編)

Ajaxで、XMLHttpRequestを利用して、自分で作ったWebサービスを、別なドメインにあるサイトから呼び出して使おうと考えたのですが、

XMLHttpRequest cannot load http://xxxx.com http://yyyy.com is not allowed by Access-Control-Allow-Origin.
Refused to get unsafe header “X-JSON”

みたいなエラーが出て、呼び出しに失敗します。。。

何だろ?と思って調べると、XMLHttpRequestの呼び出しは、同一ドメインからしかできないようになっているんですね。

これは、Cross-Origin Resource Sharing (CORS)といって、クロスドメイン間で、ブラウザにどのような振る舞いを許すかの仕様としてW3Cで規定されています。

これを回避するには、呼び出される側、つまり、Webサービス側に「Access-Control-Allow-Origin」ヘッダをつけてあげないといけません。

また、ヘッダに設定する値は、「どこからの呼び出しなら許容するか」を指定しますので、呼び出す側のURLか、「*」で全部のドメインを許容することになります。

Serveltのフィルタを使う場合

私のWebサービスはJavaのサーブレットで作成しているので、フィルタを作って、Servletのレスポンスに上記のヘッダを付加してあげることにしました。

こんな感じです。

public class CorsFilter implements Filter{
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
 
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS");
        res.setHeader("Access-Control-Allow-Headers", req.getHeader("Access-Control-Request-Headers"));
        res.setHeader("Access-Control-Max-Age", "-1");
 
        chain.doFilter(req, res);
 
    }

    public void destroy() { }
    public void init(FilterConfig filterConfig) throws ServletException { }
 
}

なお、上記のServletFilterを作成したら、web.xmlには以下のように登録しておきます。(init-rparamはとくに必要ないです。特定のGetパラメータに適用させたいときは「url-pattern」の指定だけでは適用できないので、ここで指定した「pattern」をフィルタの中で使用したりします。)

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>jp.co.xxx.xxx.servlet.CorsFilter</filter-class>
    <init-param>
        <param-name>pattern</param-name>
        <param-value>SOME_TEXT</param-value>
    </init-param>
</filter>
 
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

jspを使う場合

なお、フィルタを使うと全部のリクエストに適用されて困る!という場合は、jspなどで、特定のレスポンスに絞って適用してもいいと思います。

たとえば特定のJSPでレスポンスヘッダをセットするには、jspの暗黙オブジェクトのレスポンス(response)に以下のように設定します。

response.addHeader("Access-Control-Allow-Origin", "*");

Apacheを使う場合

ついでと言ってはなんですが、Apacheを使ったり、Apache-Tomcatで連携している人もいるかと思いますので、そちらの設定も載せておきます。

Apacheで設定を行う場合は、.htaccessに以下を記述するのが便利です。

Header append Access-Control-Allow-Origin: *

これで、サテライトの無料Blogからも自分で作ったサービスを呼ぶことができるようになりました。

Webサービスを散在させず、自サーバで一元管理できるので、今後、便利なのではないかと思います。