Comment gérer CORS en utilisant JAX-RS avec Jersey

je développe une application client Java script, côté serveur, j'ai besoin de gérer CORS, tous les services que j'avais écrits en JAX-RS avec JERSEY. Mon code:

@CrossOriginResourceSharing(allowAllOrigins = true)
@GET
@Path("/readOthersCalendar")
@Produces("application/json")
public Response readOthersCalendar(String dataJson) throws Exception {  
     //my code. Edited by gimbal2 to fix formatting
     return Response.status(status).entity(jsonResponse).header("Access-Control-Allow-Origin", "*").build();
}

A partir de Maintenant, je reçois une erreur.aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée. Origine 'http://localhost:8080' est donc pas autorisé à accéder."

Merci de m'aider avec cela.

Merci Et Salutations Bouddha Puneeth

45
demandé sur Paul Samsotha 2015-01-21 14:20:09

6 réponses

Je ne suis pas au courant d'un support standard CORS avec Jersey. @CrossOriginResourceSharing, autant que je sache, est une annotation CXF. Donc je ne suis pas vraiment sûr comment vous utilisez cette annotation avec Jersey.

avec Jersey, pour gérer CORS, j'utilise normalement un ContainerResponseFilter. ContainerResponseFilter pour Jersey 1 et 2 sont un peu différents. Puisque vous n'avez pas mentionné la version que vous utilisez, je posterai les deux.

Maillot 2

import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;

@Provider
public class CORSFilter implements ContainerResponseFilter {

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

si vous utilisez la numérisation des paquets pour découvrir les fournisseurs et les ressources, le @Provider annotation devrait prendre soin de la configuration pour vous. Si pas, alors vous aurez besoin d'inscrire explicitement ResourceConfig ou Application sous-classe.

exemple de code pour enregistrer explicitement le filtre avec le ResourceConfig:

final ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new CORSFilter());
final final URI uri = ...;
final HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(uri, resourceConfig);

Maillot 1

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

public class CORSFilter implements ContainerResponseFilter {
    @Override
    public ContainerResponse filter(ContainerRequest request,
            ContainerResponse response) {

        response.getHttpHeaders().add("Access-Control-Allow-Origin", "*");
        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");

        return response;
    }
}

web.configuration xml, vous pouvez utiliser

<init-param>
  <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
  <param-value>com.yourpackage.CORSFilter</param-value>
</init-param>

Ou ResourceConfig vous pouvez faire

resourceConfig.getContainerResponseFilters().add(new CORSFilter());

ou scannage du paquet avec @Provider annotation.


EDIT

Veuillez noter que l'exemple ci-dessus peut être amélioré. Vous aurez besoin d'en savoir plus sur le fonctionnement de CORS. Merci de voir ici. Pour un, vous obtiendrez les en-têtes pour toutes les réponses. Cela peut ne pas être souhaitable. Vous pouvez juste avoir besoin de gérer le pré-vol (ou les OPTIONS). Si vous voulez voir un filtre CORS mieux implémenté, vous pouvez vérifier le code source pour le RESTeasy CorsFilter


UPDATE

J'ai donc décidé d'ajouter une implémentation plus correcte. L'implémentation ci-dessus est paresseuse et ajoute tous les en-têtes CORS à toutes les requêtes. L'autre erreur est que c'est seulement un réponse filtre, la requête est encore en cours de traitement. Cela signifie que lorsque la requête preflight arrive, ce qui est une requête D'OPTIONS, il n'y aura pas de méthode D'OPTIONS implémentée, donc nous obtiendrons une réponse 405, ce qui est incorrect.

Voici comment il devrait travail. Il existe donc deux types de requêtes CORS: les requêtes simples et contrôle en amont des demandes d'. Pour une requête simple, le navigateur enverra la requête réelle et ajoutera le Origin en-tête de requête. Le navigateur attend la réponse pour avoir le Access-Control-Allow-Origin en-tête, en disant que l'origine de la Origin en-tête est autorisé. Pour être considérée comme une" simple demande", elle doit satisfaire aux conditions suivantes: critères:

  • Être l'une des méthodes suivantes:
    • GET
    • tête
    • POST
  • outre les en-têtes définis automatiquement par le navigateur, la requête ne peut contenir que les manuellement définir les en-têtes:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Save-Data
    • Viewport-Width
    • Width
  • Les seules valeurs autorisées pour l' Content-Type header:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Si la demande ne répond pas à ces trois critères, une demande avant le vol est faite. C'est une demande qui est faite au serveur, avant à la réelle demande. Il contiendra différent Access-Control-XX-XX headers, et le serveur doit répondre à ces headers avec ses propres headers de réponse CORS. Voici les en-têtes correspondants:

                 Preflight Request and Response Headers
+-----------------------------------+--------------------------------------+
|  REQUEST HEADER                   |  RESPONSE HEADER                     |
+===================================+======================================+
|  Origin                           |  Access-Control-Allow-Origin         |
+-----------------------------------+--------------------------------------+
|  Access-Control-Request-Headers   |  Access-Control-Allow-Headers        |
+-----------------------------------+--------------------------------------+
|  Access-Control-Request-Method    |  Access-Control-Allow-Methods        |
+-----------------------------------+--------------------------------------+
|  XHR.withCredentials              |  Access-Control-Allow-Credentials    |
+-----------------------------------+--------------------------------------+
  • Origin en-tête de la requête, la valeur sera le domaine du serveur d'origine, et la réponse Access-Control-Allow-Header doivent être à cette même adresse ou * préciser que toutes les origines sont permises.

  • si le client essaie de définir manuellement les en-têtes qui ne sont pas dans la liste ci-dessus, alors le navigateur va définir le Access-Control-Request-Headers en-tête, avec la valeur étant une liste de tous les en-têtes que le client tente de définir. Le serveur doit répondre de retour avec un Access-Control-Allow-Headers en-tête de réponse, la valeur étant une liste d'en-têtes qu'elle autorise.

  • le navigateur définira également Access-Control-Request-Method en-tête de requête, la valeur étant la méthode HTTP de la requête. Le serveur doit répondre avec l' Access-Control-Allow-Methods en-tête de réponse, la valeur étant une liste des méthodes qu'elle autorise.

  • Si le client utilise le XHR.withCredentials, alors le serveur devrait répondre avec le Access-Control-Allow-Credentials en-tête de réponse, avec une valeur de true. Lire la suite ici.

Donc, avec tout cela dit, voici une meilleure mise en œuvre. Même bien que ce soit mieux que l'implémentation ci-dessus, elle est encore inférieure à la RESTEasy à laquelle j'ai relié, car cette implémentation permet encore Toutes les origines. Mais ce filtre fait un meilleur travail pour adhérer à la spécification CORS que le filtre ci-dessus qui ajoute simplement les en-têtes de réponse CORS à toutes les requêtes. Notez que vous pouvez aussi avoir besoin de modifier le Access-Control-Allow-Headers pour faire correspondre les en-têtes que votre application permettra; Vous pouvez vouloir ajouter ou supprimer certains en-têtes de la liste dans cette exemple.

@Provider
@PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {

    /**
     * Method for ContainerRequestFilter.
     */
    @Override
    public void filter(ContainerRequestContext request) throws IOException {

        // If it's a preflight request, we abort the request with
        // a 200 status, and the CORS headers are added in the
        // response filter method below.
        if (isPreflightRequest(request)) {
            request.abortWith(Response.ok().build());
            return;
        }
    }

    /**
     * A preflight request is an OPTIONS request
     * with an Origin header.
     */
    private static boolean isPreflightRequest(ContainerRequestContext request) {
        return request.getHeaderString("Origin") != null
                && request.getMethod().equalsIgnoreCase("OPTIONS");
    }

    /**
     * Method for ContainerResponseFilter.
     */
    @Override
    public void filter(ContainerRequestContext request, ContainerResponseContext response)
            throws IOException {

        // if there is no Origin header, then it is not a
        // cross origin request. We don't do anything.
        if (request.getHeaderString("Origin") == null) {
            return;
        }

        // If it is a preflight request, then we add all
        // the CORS headers here.
        if (isPreflightRequest(request)) {
            response.getHeaders().add("Access-Control-Allow-Credentials", "true");
            response.getHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
            response.getHeaders().add("Access-Control-Allow-Headers",
                // Whatever other non-standard/safe headers (see list above) 
                // you want the client to be able to send to the server,
                // put it in this list. And remove the ones you don't want.
                "X-Requested-With, Authorization, " +
                "Accept-Version, Content-MD5, CSRF-Token");
        }

        // Cross origin requests can be either simple requests
        // or preflight request. We need to add this header
        // to both type of requests. Only preflight requests
        // need the previously added headers.
        response.getHeaders().add("Access-Control-Allow-Origin", "*");
    }
}

pour en savoir plus sur CORS, je vous suggère de lire les documents du MDN sur cross-Origin Resource Sharing (CORS)

113
répondu Paul Samsotha 2018-09-26 03:42:36

L'autre réponse pourrait être rigoureusement exacte, mais trompeuse. La partie manquante est que vous pouvez mélanger des filtres provenant de différentes sources. Même pensé Jersey pourrait ne pas fournir CORS filtre (pas un fait que j'ai vérifié, mais je fais confiance à l'autre réponse sur ce), vous pouvez utiliser tomcat propre CORS du filtre.

je l'utilise avec succès avec Jersey. J'ai ma propre implémentation de Basic Authentication filter, par exemple, avec CORS. Mieux que tout, CORS filter est configuré en Web XML, pas en code.

3
répondu Michael 2016-05-13 08:39:07

la réponse de peeskillet est correcte. Mais j'obtiens cette erreur lors du rafraîchissement de la page web (cela ne fonctionne qu'au premier chargement):

The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed. Origin 'http://127.0.0.1:8080' is therefore not allowed access.

donc au lieu d'utiliser la méthode add pour ajouter des en-têtes pour répondre, j'utilise la méthode put. C'est ma classe

public class MCORSFilter implements ContainerResponseFilter {
    public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
    public static final String ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*";

    private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
    private static final String ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE = "true";

    public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
    public static final String ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept";

    public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
    public static final String ACCESS_CONTROL_ALLOW_METHODS_VALUE = "GET, POST, PUT, DELETE, OPTIONS, HEAD";

    public static final String[] ALL_HEADERs = {
            ACCESS_CONTROL_ALLOW_ORIGIN,
            ACCESS_CONTROL_ALLOW_CREDENTIALS,
            ACCESS_CONTROL_ALLOW_HEADERS,
            ACCESS_CONTROL_ALLOW_METHODS
    };
    public static final String[] ALL_HEADER_VALUEs = {
            ACCESS_CONTROL_ALLOW_ORIGIN_VALUE,
            ACCESS_CONTROL_ALLOW_CREDENTIALS_VALUE,
            ACCESS_CONTROL_ALLOW_HEADERS_VALUE,
            ACCESS_CONTROL_ALLOW_METHODS_VALUE
    };
    @Override
    public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
        for (int i = 0; i < ALL_HEADERs.length; i++) {
            ArrayList<Object> value = new ArrayList<>();
            value.add(ALL_HEADER_VALUEs[i]);
            response.getHttpHeaders().put(ALL_HEADERs[i], value); //using put method
        }
        return response;
    }
}

et ajoutez cette classe à init-param dans web.xml

<init-param>
            <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
            <param-value>com.yourpackage.MCORSFilter</param-value>
        </init-param>
1
répondu die_for_rock_vn 2016-09-08 11:13:29

Supprimer l'annotation"@CrossOriginResourceSharing(allowAllOrigins = true)"

Ensuite, de Retour de Réponse, comme ci-dessous:

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

Mais jsonResponse doit être remplacé par un objet POJO!

1
répondu Aupr 2017-11-25 07:23:28

Pour résoudre ce pour mon projet j'ai utilisé Michael réponse et est arrivé à ceci:

    <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <executions>
            <execution>
                <id>run-embedded</id>
                <goals>
                    <goal>run</goal>
                </goals>
                <phase>pre-integration-test</phase>
                <configuration>
                    <port>${maven.tomcat.port}</port>
                    <useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
                    <contextFile>${project.basedir}/tomcat/context.xml</contextFile>
                    <!--enable CORS for development purposes only. The web.xml file specified is a copy of
                        the auto generated web.xml with the additional CORS filter added -->
                    <tomcatWebXml>${maven.tomcat.web-xml.file}</tomcatWebXml>
                </configuration>
            </execution>
        </executions>
    </plugin>

le filtre CORS étant l'exemple de base du filtre de le site tomcat.



Modifier:

maven.tomcat.Web-xml.le fichier variable est une propriété définie par pom pour le projet et elle contient le chemin vers le web.fichier xml (situé à l'intérieur de mon projet)

0
répondu Dark Star1 2017-05-23 12:02:29

en utilisant JAX-RS vous pouvez simplement ajouter l'annotation @CrossOrigin(origin = yourURL) pour votre contrôleur de ressources. Dans votre cas, serait @CrossOrigin(origin = "http://localhost:8080") mais vous pouvez également utiliser @CrossOrigin(origin = "*") pour permettre à n'importe quelle demande de passer par votre service web.

Vous pouvez le vérifier pour plus d'informations.

-3
répondu AdevaS 2017-01-12 13:28:35