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
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.
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
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
.
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.
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:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Save-Data
Viewport-Width
Width
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.
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.
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>
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).
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!