webentwicklung-frage-antwort-db.com.de

Umgang mit CORS mit JAX-RS mit Jersey

Ich entwickle eine Java-Skript-Clientanwendung. Auf der Serverseite muss ich mit CORS umgehen, all den Services, die ich in JAX-RS mit JERSEY geschrieben hatte.

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

Ab jetzt erhalte ich die Fehlermeldung Es ist kein Header "Access-Control-Allow-Origin" auf der angeforderten Ressource vorhanden. Origin ' http: // localhost: 8080 ' hat daher keinen Zugriff. "

Bitte hilf mir dabei.

Vielen Dank und Grüße Buddha Puneeth

53
user2773716

Hinweis: Lesen Sie das UPDATE unten.

@CrossOriginResourceSharing ist eine CXF-Anmerkung, daher funktioniert sie nicht mit Jersey. 

Um mit CORS zu arbeiten, benutze ich normalerweise nur eine ContainerResponseFilter . Die ContainerResponseFilter für Jersey 1 und 2 sind etwas anders. Da Sie nicht erwähnt haben, welche Version Sie verwenden, werde ich beides veröffentlichen.

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

Wenn Sie die Paketsuche verwenden, um Anbieter und Ressourcen zu ermitteln, sollte die Annotation @Provider die Konfiguration für Sie übernehmen. Wenn nicht, müssen Sie sie explizit bei der Unterklasse ResourceConfig oder Application registrieren.

Beispielcode zum expliziten Registrieren eines Filters mit der Variablen ResourceConfig:

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

Wenn Sie bei Jersey 2.x Probleme bei der Registrierung dieses Filters haben, finden Sie hier einige Ressourcen, die möglicherweise hilfreich sind

Jersey 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.xml Konfiguration können Sie verwenden 

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

Oder ResourceConfig kannst du tun

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

Oder das Scannen von Paketen mit der Annotation @Provider.


BEARBEITEN

Bitte beachten Sie, dass das obige Beispiel verbessert werden kann. Sie müssen mehr darüber wissen, wie CORS funktioniert. Bitte sehen Sie hier . Zum einen erhalten Sie die Header für alle Antworten. Dies ist möglicherweise nicht wünschenswert. Möglicherweise müssen Sie nur mit dem Preflight (oder den Optionen) arbeiten. Wenn Sie einen besser implementierten CORS-Filter sehen möchten, können Sie den Quellcode für das RESTeasy CorsFilter auschecken.


AKTUALISIEREN

Also entschied ich mich, eine korrektere Implementierung hinzuzufügen. Die obige Implementierung ist faul und fügt allen Anforderungen alle CORS-Header hinzu. Der andere Fehler ist, dass die Anforderung immer noch verarbeitet wird, da es sich nur um einen Antwort Filter handelt. Das heißt, wenn die Preflight-Anfrage eingeht, bei der es sich um eine OPTIONS-Anfrage handelt, wird keine OPTIONS-Methode implementiert, sodass wir eine 405-Antwort erhalten, die falsch ist.

So funktioniert es sollte. Es gibt also zwei Arten von CORS-Anforderungen: einfache Anforderungen und Preflight-Anforderungen . Bei einer einfachen Anfrage sendet der Browser die aktuelle Anfrage und fügt den Anforderungsheader Origin hinzu. Der Browser erwartet für die Antwort den Header Access-Control-Allow-Origin, der besagt, dass der Ursprung aus dem Header Origin zulässig ist. Damit es als "einfache Anfrage" betrachtet werden kann, muss es die folgenden Kriterien erfüllen:

  • Seien Sie eine der folgenden Methoden:
    • GET
    • HEAD
    • POST
  • Abgesehen von Header, die automatisch vom Browser gesetzt werden, darf die Anfrage nur die folgenden manuell Set-Header enthalten:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Save-Data
    • Viewport-Width
    • Width
  • Die einzigen zulässigen Werte für den Content-Type-Header sind:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Wenn die Anforderung nicht alle drei Kriterien erfüllt, wird eine Preflight-Anforderung erstellt. Dies ist eine OPTIONS-Anforderung, die an den Server gesendet wird, vorher an die tatsächlich angeforderte Anforderung. Es enthält verschiedene Access-Control-XX-XX-Header, und der Server sollte auf diese Header mit eigenen CORS-Response-Headern antworten. Hier sind die passenden Header:

                 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    |
+-----------------------------------+--------------------------------------+
  • Mit dem Anforderungsheader Origin ist der Wert die Ursprungsserverdomäne, und die Antwort Access-Control-Allow-Header sollte entweder dieselbe Adresse sein oder *, um anzugeben, dass alle Ursprünge zulässig sind.

  • Wenn der Client versucht, Kopfzeilen, die nicht in der obigen Liste enthalten sind, manuell festzulegen, setzt der Browser die Access-Control-Request-Headers-Kopfzeile, wobei der Wert eine Liste aller Kopfzeilen ist, die der Client festlegen möchte. Der Server sollte mit einem Access-Control-Allow-Headers-Antwortheader antworten, wobei der Wert eine Liste von Headern ist, die er zulässt.

  • Der Browser setzt auch den Anforderungsheader Access-Control-Request-Method, wobei der Wert die HTTP-Methode der Anforderung ist. Der Server sollte mit dem Access-Control-Allow-Methods-Antwortheader antworten, wobei der Wert eine Liste der zulässigen Methoden ist.

  • Wenn der Client den XHR.withCredentials verwendet, sollte der Server mit dem Access-Control-Allow-Credentials-Antwortheader mit dem Wert true antworten. Lesen Sie hier mehr .

Mit all dem gesagt, hier ist eine bessere Implementierung. Obwohl dies besser als die obige Implementierung ist, ist es dem RESTEasy one I, dem es zugeordnet ist, immer noch unterlegen, da diese Implementierung noch alle Ursprünge zulässt. Dieser Filter hält sich jedoch besser an die CORS-Spezifikation als der obige Filter, der lediglich die CORS-Antwortheader zu allen Anforderungen hinzufügt. Beachten Sie, dass Sie möglicherweise auch Access-Control-Allow-Headers ändern müssen, um den Kopfzeilen zu entsprechen, die Ihre Anwendung zulässt. In diesem Beispiel können Sie einige Header aus der Liste hinzufügen oder entfernen.

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

Um mehr über CORS zu erfahren, schlage ich vor, die MDN-Dokumente auf Cross-Origin Resource Sharing (CORS) zu lesen.

132
Paul Samsotha

Die andere Antwort mag streng korrekt sein, aber irreführend. Der fehlende Teil ist, dass Sie Filter aus verschiedenen Quellen zusammen mischen können. Auch wenn Jersey möglicherweise keinen CORS-Filter zur Verfügung stellt (nicht eine Tatsache, die ich überprüft habe, aber ich vertraue der anderen Antwort darauf), können Sie Tomcat's eigenen CORS-Filter verwenden.

Ich benutze es erfolgreich mit Jersey. Ich habe meine eigene Implementierung des Basisauthentifizierungsfilters zum Beispiel zusammen mit CORS. Das Beste ist, dass der CORS-Filter in Web-XML und nicht im Code konfiguriert ist.

4
Michael

peeskillets Antwort ist richtig. Ich erhalte jedoch diese Fehlermeldung, wenn die Webseite aktualisiert wird (sie funktioniert nur beim ersten Laden):

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.

Anstatt die Methode add zum Hinzufügen von Headern für die Antwort zu verwenden, verwende ich die put-Methode. Das ist meine Klasse

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

Fügen Sie diese Klasse in web.xml zu init-param hinzu

<init-param>
            <param-name>com.Sun.jersey.spi.container.ContainerResponseFilters</param-name>
            <param-value>com.yourpackage.MCORSFilter</param-value>
        </init-param>
1
die_for_rock_vn

Um dies für mein Projekt zu lösen, habe ich Micheal's answer verwendet und bin zu folgendem Ergebnis gekommen:

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

Der CORS-Filter ist der grundlegende Beispielfilter von der Tomcat-Site.

Bearbeiten:
Die Variable maven.Tomcat.web-xml.file ist eine von pom definierte Eigenschaft für das Projekt. Sie enthält den Pfad zur Datei web.xml (in meinem Projekt).

1
Dark Star1

Annotation "@CrossOriginResourceSharing(allowAllOrigins = true)" entfernen

Dann antworten Sie bitte wie folgt:

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

Die jsonResponse sollte jedoch durch ein POJO-Objekt ersetzt werden!

1
Aupr