web-dev-qa-db-fra.com

Comment activer les demandes interdomaines sur les services Web JAX-RS?

J'ai développé un ensemble de services Web reposants. Je ne pouvais appeler aucune de ces méthodes à partir de clients distants en raison de l'erreur No 'Access-Control-Allow-Origin' header is present on the requested resource.

Les services fonctionnent parfaitement sur localhost. Y at-il des modifications ou des configurations à faire du côté serveur pour résoudre le problème c'est-à-dire pour activer les requêtes entre domaines.

J'utilise WildFly 8, JavaEE 7 

59
Naili

Je me demandais la même chose. Après quelques recherches, j’ai trouvé que le moyen le plus simple était tout simplement d’utiliser une variable JAX-RS ContainerResponseFilter pour ajouter les en-têtes CORS pertinents. Ainsi, vous n'avez pas besoin de remplacer l'ensemble de la pile de services Web par CXF (Wildfly utilise CXF, c'est une forme, mais il ne semble pas qu'elle l'utilise pour JAX-RS, peut-être uniquement JAX-WS).

Peu importe si vous utilisez ce filtre, les en-têtes seront ajoutés à chaque service Web REST.

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");
   }

}

Ensuite, lorsque j'ai testé avec curl, la réponse contenait les en-têtes 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

Si j'ai bien compris, c'est l'annotation @Provider qui indique au moteur d'exécution JAX-RS d'utiliser le filtre, sans l'annotation, rien ne se produit.

J'ai eu l'idée d'utiliser la variable ContainerResponseFilter d'un exemple de Jersey .

96
Joel Pearson

J'étais confronté à un problème similaire et j'avais essayé d'utiliser la solution solution d'Alex Petty, mais je devais définir les en-têtes CORS sur chaque terminal JAX-RS de ma classe, en tant que tels:

@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();
}

Je devais définir plus avant un point final OPTIONS fourre-tout qui renverrait les en-têtes CORS pour toute autre demande OPTIONS de la classe et capturerait ainsi tous les points finaux de la sorte:

@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();
}

Ce n’est qu’après cela que je pourrai utiliser correctement mes points de terminaison API JAX-RS à partir de clients Jquery Ajax sur d’autres domaines ou hôtes.

16
nemesisfixx

J'ai trouvé un moyen encore plus simple (spécifique à RestEasy) d'activer CORS sous Wildfly sans utiliser de filtre et de contrôler la configuration de l'en-tête de réponse de votre API au niveau des ressources.

Par exemple:

@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

J'ai eu de la chance en configurant le partage de ressources inter-origines (CORS) pour mon API (sur Wildfly) en utilisant cette bibliothèque:

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

C'est très facile à installer. Ajoutez simplement la dépendance ci-dessus à votre pom, puis ajoutez la configuration suivante à la section webapp de votre fichier web.xml.

<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>

Vous pouvez également le configurer avec un fichier de propriétés à la place si vous préférez. Cette lib fonctionne comme un charme et vous donne beaucoup de flexibilité de configuration!

10
Alex Petty

Aucune des autres réponses n'a fonctionné pour moi, mais cela a fonctionné:

import javax.ws.rs.core.Response;

Modifiez ensuite le type de retour de la méthode de service en Response et modifiez l'instruction return en

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

resp est l'objet de réponse d'origine.

7
Alex R

Vous pouvez également implémenter javax.ws.rs.core.Feature comme ci-dessous pour implémenter 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

Juste pour ajouter quelque chose à d'autres réponses. Autoriser * est un peu dangereux . Ce qui peut être fait est de configurer une base de données de l'origine autorisée (cela peut être un fichier)

Ensuite, lorsque la demande arrive, vous pouvez faire:

// 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");
}

De cette façon, vous ne permettrez pas à tout le monde.

0
Geoffrey

La réponse de @Joel Pearson a aidé, mais pour quelqu'un qui est nouveau dans JAX-RS comme moi et qui exécute le service sur Tomcat en configurant web.xml, il faut être prudent lors de la création de la classe et de son insertion n'importe où dans le projet. Reportez-vous au package que vous avez spécifié ci-dessous pour le maillot et créez-y cette classe de filtre. De cette façon, cela a fonctionné pour moi.

0
Novice_JS