web-dev-qa-db-ja.com

JAX-RS Webサービスでクロスドメインリクエストを有効にする方法

安らかなWebサービスのセットを開発しました。エラーNo 'Access-Control-Allow-Origin' header is present on the requested resource.が原因で、これらのメソッドをリモートクライアントから呼び出すことができませんでした

サービスはローカルホストで完全に機能します。問題を解決するためにサーバー側で行う変更や設定はありますか?つまり、クロスドメインリクエストを有効にします。

WildFly 8、JavaEE 7を使用しています

64
Naili

私は同じことを疑問に思っていたので、少し調査した後、最も簡単な方法は、JAX-RS ContainerResponseFilterを使用して関連するCORSヘッダーを追加することであることがわかりました。この方法では、Webサービススタック全体をCXFに置き換える必要はありません(WildflyはCXFを使用していますが、JAX-RSに使用するようには見えないかもしれません)。

このフィルターを使用するかどうかに関係なく、すべてのREST Webサービスにヘッダーが追加されます。

package com.yourdomain.package;

import Java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;

@Provider
public class CORSFilter implements ContainerResponseFilter {

   @Override
   public void filter(final ContainerRequestContext requestContext,
                      final ContainerResponseContext cres) throws IOException {
      cres.getHeaders().add("Access-Control-Allow-Origin", "*");
      cres.getHeaders().add("Access-Control-Allow-Headers", "Origin, content-type, accept, authorization");
      cres.getHeaders().add("Access-Control-Allow-Credentials", "true");
      cres.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
      cres.getHeaders().add("Access-Control-Max-Age", "1209600");
   }

}

それからcurlでテストしたとき、応答にはCORSヘッダーがありました:

$ curl -D - "http://localhost:8080/rest/test"
HTTP/1.1 200 OK
X-Powered-By: Undertow 1
Access-Control-Allow-Headers: Origin, content-type, accept, authorization
Server: Wildfly 8
Date: Tue, 13 May 2014 12:30:00 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Transfer-Encoding: chunked
Content-Type: application/json
Access-Control-Max-Age: 1209600
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, HEAD

私の理解では、@ProviderアノテーションがJAX-RSランタイムにフィルターを使用するように指示しますが、アノテーションなしでは何も起こりません。

Jerseyの例 からContainerResponseFilterを使用するというアイデアを得ました。

101
Joel Pearson

私は同様の問題に直面しており、@ Alex Pettyの solution を使用しようとしましたが、クラスの各JAX-RSエンドポイントにCORSヘッダーを設定する必要があることは別として、

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getMemberList() {
    List<Member> memberList = memberDao.listMembers();
    members.addAll(memberList);
    return Response
            .status(200)
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Headers", "Origin, content-type, accept, authorization")
            .header("Access-Control-Allow-Credentials", "true")
            .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
            .header("Access-Control-Max-Age", "1209600")
            .entity(memberList)
            .build();
}

クラス内の他のOPTIONSリクエストに対してCORSヘッダーを返すcatch-all OPTIONSエンドポイントをさらに定義する必要があったため、並べ替えのすべてのエンドポイントをキャッチしました。

@OPTIONS
@Path("{path : .*}")
public Response options() {
    return Response.ok("")
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Headers", "Origin, content-type, accept, authorization")
            .header("Access-Control-Allow-Credentials", "true")
            .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
            .header("Access-Control-Max-Age", "1209600")
            .build();
}

これを行った後にのみ、他のドメインまたはホスト上のJquery AjaxクライアントからJAX-RS APIエンドポイントを適切に使用できます。

16
nemesisfixx

フィルターを使用せずにWildflyでCORSを有効にし、リソースレベルでAPI応答ヘッダー構成を制御できる、さらに簡単な(RestEasy固有の)方法を見つけました。

例えば:

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getMemberList() {
    List<Member> memberList = memberDao.listMembers();
    members.addAll(memberList);
    return Response
            .status(200)
            .header("Access-Control-Allow-Origin", "*")
            .header("Access-Control-Allow-Headers", "Origin, content-type, accept, authorization")
            .header("Access-Control-Allow-Credentials", "true")
            .header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
            .header("Access-Control-Max-Age", "1209600")
            .entity(memberList)
            .build();
}
11
Alex Petty

このライブラリを使用して、(Wildflyで)APIのCross-Originリソース共有(CORS)を設定できました。

<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.1</version>
</dependency>

設定はとても簡単です。上記の依存関係をpomに追加してから、次の構成をweb.xmlファイルのwebappセクションに追加します。

<filter>
    <filter-name>CORS</filter-name>
    <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>

    <init-param>
        <param-name>cors.allowGenericHttpRequests</param-name>
        <param-value>true</param-value>
    </init-param>

    <init-param>
        <param-name>cors.allowOrigin</param-name>
        <param-value>*</param-value>
    </init-param>

    <init-param>
        <param-name>cors.allowSubdomains</param-name>
        <param-value>false</param-value>
    </init-param>

    <init-param>
        <param-name>cors.supportedMethods</param-name>
        <param-value>GET, HEAD, POST, DELETE, OPTIONS</param-value>
    </init-param>

    <init-param>
        <param-name>cors.supportedHeaders</param-name>
        <param-value>*</param-value>
    </init-param>

    <init-param>
        <param-name>cors.supportsCredentials</param-name>
        <param-value>true</param-value>
    </init-param>

    <init-param>
        <param-name>cors.maxAge</param-name>
        <param-value>3600</param-value>
    </init-param>

</filter>

<filter-mapping>
    <!-- CORS Filter mapping -->
    <filter-name>CORS</filter-name>
    <url-pattern>*</url-pattern>
</filter-mapping>

必要に応じて、代わりにプロパティファイルを使用して構成することもできます。このライブラリは魅力のように機能し、設定の柔軟性が大幅に向上します!

10
Alex Petty

他の答えはどれもうまくいきませんでしたが、これはうまくいきました:

import javax.ws.rs.core.Response;

次に、サービスメソッドの戻り値の型をResponseに変更し、returnステートメントを次のように変更します。

return Response.ok(resp).header("Access-Control-Allow-Origin", "*").build();

ここで、respは元の応答オブジェクトです。

7
Alex R

以下のようにjavax.ws.rs.core.Featureを実装して、CORSを実装することもできます。

import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
import org.jboss.resteasy.plugins.interceptors.CorsFilter;

@Provider
 public class CorsFeature implements Feature {

  @Override
  public boolean configure(FeatureContext context) {
    CorsFilter corsFilter = new CorsFilter();
    corsFilter.getAllowedOrigins().add("*");
    context.register(corsFilter);
    return true;
 }

}
3
Ranuka

他の応答に何かを追加するだけです。 *を許可することは少し危険です。できることは、許可されたオリジンのデータベースを構成することです(ファイルにすることもできます)

その後、リクエストが到着すると次のことができます。

// this will return you the Origin 
String referers[] = requestContext.getHeaders().get("referer")
// then search in your DB if the Origin is allowed
if(referers != null && referers.lenght == 1 && isAllowedOriging(referers[0])){
        containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", referers[0]);
        containerResponseContext.getHeaders().add("Access-Control-Allow-Headers", "Origin, content-type, accept, authorization, <HERE PUT YOUR DEDICATED HEADERS>);
        containerResponseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
        containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        containerResponseContext.getHeaders().add("Access-Control-Max-Age", "1209600");
}

その方法では、すべての人を許可しません。

0
Geoffrey

@Joel Pearsonの回答は役に立ちましたが、私のようなJAX-RSを初めて使用し、web.xmlを構成してTomcatでサービスを実行している人は、クラスを作成してプロジェクトのどこにでも配置する際に注意する必要があります。 jerseyで指定したパッケージを参照して、このフィルタークラスを作成します。そのようにそれは私のために働いた。

0
Novice_JS