Как включить Междоменные запросы на веб-службах JAX-RS?


Я разработал набор веб-сервисов restful. Я не мог вызвать ни один из этих методов из удаленных клиентов из-за ошибки No 'Access-Control-Allow-Origin' header is present on the requested resource.

сервисы отлично работают на localhost. Есть ли какие-либо изменения или конфиги на сервер чтобы решить эту проблему. т. е. включить междоменные запросы.

Я использую WildFly 8, JavaEE 7

8 54

8 ответов:

мне было интересно то же самое, поэтому после небольшого исследования я обнаружил, что самый простой способ-просто использовать JAX-RS ContainerResponseFilter для добавления соответствующих заголовков CORS. Таким образом, вам не нужно заменять весь стек веб-сервисов на CXF (Wildfly использует CXF в какой-то форме, но не похоже, что он использует его для JAX-RS, возможно, только JAX-WS).

независимо от того, используете ли вы этот фильтр, он добавит заголовки к каждому веб-сервису 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");
   }

}

потом, когда я тестировал с 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 использовать фильтр, без аннотации ничего не происходит.

у меня есть идея об использовании ContainerResponseFilter С пример-Джерси.

я столкнулся с аналогичной проблемой, и попытался использовать @Alex Petty's решение, но помимо того, чтобы установить заголовки CORS на каждой конечной точке JAX-RS в моем классе, как таковой:

@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 для любого другого 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();
}

только после этого я мог бы правильно использовать свои конечные точки API JAX-RS от Клиенты jQuery Ajax на других доменах или хостах.

Я нашел еще более простой (RestEasy-specific) способ включить CORS на Wildfly без использования фильтра и где вы можете управлять конфигурацией заголовка ответа API на уровне ресурсов.

например:

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

мне повезло настроить общий доступ к ресурсам Cross-origin (CORS) для моего API (на Wildfly) с помощью этой библиотеки:

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

это очень легко настроить. Просто добавьте вышеуказанную зависимость в свой pom, а затем добавьте следующую конфигурацию в раздел webapp вашего интернета.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>

вы также можете настроить его с помощью файла свойств, если вы предпочитаете. Эта библиотека работает как шарм и дает вам много гибкости конфигурации!

ни один из других ответов не работал для меня, но это было:

import javax.ws.rs.core.Response;

затем измените тип возврата метода службы на Response, и изменить return заявление:

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

здесь resp является исходным объектом ответа.

можно использовать 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;
 }

}

просто чтобы добавить что-то к другим ответам. Разрешение * немного опасно. Что можно сделать, так это настроить базу данных разрешенного происхождения (это может быть файл)

затем, когда запрос прибудет вы можете сделать:

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

таким образом, вы не позволите всем.

@Joel Pearson ответ помог, но для кого-то, кто новичок в JAX-RS, как я, и запускает службу на tomcat, настроив web.xml должен быть осторожным при создании класса и размещении его в любом месте проекта. См. пакет, указанный в разделе для Джерси, и создайте там этот класс фильтра. Таким образом, это сработало для меня.