使用JAX-RS/RESTEasy实现CORS的Ajax请求

使用JAX-RS/RESTEasy实现CORS的Ajax请求,ajax,json,jax-rs,resteasy,cors,Ajax,Json,Jax Rs,Resteasy,Cors,我有两台服务器(Apache和JBoss AS7),我需要向客户机提供对所有http方法的访问。所有这些请求都必须通过ajax发送。 客户机代码示例: $.ajax({ type: "get", url: "http://localhost:9080/myproject/services/mobile/list", crossDomain: true, cache: false, dataType: "json", succ

我有两台服务器(Apache和JBoss AS7),我需要向客户机提供对所有http方法的访问。所有这些请求都必须通过ajax发送。 客户机代码示例:

$.ajax({
      type: "get",
      url: "http://localhost:9080/myproject/services/mobile/list",
      crossDomain: true,
      cache: false,
      dataType: "json",
      success: function(response) {
        console.log(response);
      },
      error: function (jqXHR, textStatus, errorThrown) {
        console.log(textStatus);
        console.log(jqXHR.responseText);
        console.log(errorThrown);
        }
    });
在JBoss AS7中,我使用RESTEasy,实现CORS如下:

@Path("/mobile")
@Provider
@ServerInterceptor
public class GroupMobile implements MessageBodyWriterInterceptor {

@Inject
private GroupDAO groupDAO;

@GET
@Path("/list")
@Produces(MediaType.APPLICATION_JSON)
public List<Group> getGroups() {
    return groupDAO.listAll();
}

@Override
public void write(MessageBodyWriterContext context) throws IOException,
        WebApplicationException {
    context.getHeaders().add("Access-Control-Allow-Origin", "*");
    context.proceed();
}

@OPTIONS
@Path("/{path:.*}")
public Response handleCORSRequest(
        @HeaderParam("Access-Control-Request-Method") final String requestMethod,
        @HeaderParam("Access-Control-Request-Headers") final String requestHeaders) {
    final ResponseBuilder retValue = Response.ok();

    if (requestHeaders != null)
        retValue.header("Access-Control-Allow-Headers", requestHeaders);

    if (requestMethod != null)
        retValue.header("Access-Control-Allow-Methods", requestMethod);

    retValue.header("Access-Control-Allow-Origin", "*");

    return retValue.build();
}
}

有人知道哪里出了问题吗?

您遇到的问题是您正在尝试进行跨站点脚本编写。您在
http://MyIP:8080
因此浏览器阻止您访问该域以外的资源。这是非常特定于浏览器的,基于浏览器的解决方案将完全不同(您可以在Chrome中全局禁用安全性,在IE中基于每个站点禁用安全性)


如果您以
http://localhost:8080
,则应允许您访问查询。或者,您可以实现一个将转发请求的代理。

听起来问题与此相关。您可能无法使用
MessageBodyWriterInterceptor
捕获CORS飞行前请求。尝试改用servlet过滤器(
@WebFilter
)。

好吧,我已经实现了一个小的解决方案,首先我在我的project Web中做了一个拦截器 我创建了一个名为“CORSInterceptor”的类,该类就是这样

import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.core.ResourceMethod;
import org.jboss.resteasy.core.ServerResponse;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.interception.MessageBodyWriterContext;
import org.jboss.resteasy.spi.interception.MessageBodyWriterInterceptor;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Provider
@ServerInterceptor
public class CorsInterceptor implements PreProcessInterceptor, MessageBodyWriterInterceptor {

/**
     * The Origin header set by the browser at each request.
     */
    private static final String ORIGIN = "Origin";


 /**
     * The Access-Control-Allow-Origin header indicates which origin a resource it is specified for can be
     * shared with. ABNF: Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" source origin string | "*"
     */
    private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";


   //
    private static final ThreadLocal<String> REQUEST_ORIGIN = new ThreadLocal<String>();
    //
    private final Set<String> allowedOrigins;


 public CorsInterceptor(){
   this.allowedOrigins = new HashSet<String>();
   this.allowedOrigins.add("*");
 }

   @Override
    public ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException {
        if (!allowedOrigins.isEmpty()) {
            REQUEST_ORIGIN.set(request.getHttpHeaders().getRequestHeaders().getFirst(ORIGIN));
        }
        return null;
    }


@Override
public void write(MessageBodyWriterContext context) throws IOException, WebApplicationException {
    if (!allowedOrigins.isEmpty() && (allowedOrigins.contains(REQUEST_ORIGIN.get()) || allowedOrigins.contains("*"))) {
        context.getHeaders().add(ACCESS_CONTROL_ALLOW_ORIGIN, REQUEST_ORIGIN.get());
      }
    context.proceed();
    }
}
这对我很管用。我希望它能帮助您。

最新的resteasy(3.0.9-Final)包括一个实用类
org.jboss.resteasy.plugins.interceptors.CorsFilter

您可以将CorsFilter对象添加到应用程序的singleton中 对象集,或将其添加到ResteasyDeployment中的ProviderFactory中 直接的

以下是示例应用程序类:

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;

import org.jboss.resteasy.plugins.interceptors.CorsFilter;


@ApplicationPath("/api")
public class RestApplication extends javax.ws.rs.core.Application {
    Set<Object> singletons;

    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> clazzes = new HashSet<>();
        clazzes.add(VersionService.class);
        return clazzes;
    }

    @Override
    public Set<Object> getSingletons() {
        if (singletons == null) {
            CorsFilter corsFilter = new CorsFilter();
            corsFilter.getAllowedOrigins().add("*");

            singletons = new LinkedHashSet<Object>();
            singletons.add(corsFilter);
        }
        return singletons;
    }
}
import java.util.HashSet;
导入java.util.Set;
导入javax.ws.rs.ApplicationPath;
导入org.jboss.resteasy.plugins.interceptors.CorsFilter;
@应用程序路径(“/api”)
公共类重新启动应用程序扩展了javax.ws.rs.core.Application{
设置单身人士;
@凌驾
public Set>clazzes=new HashSet();
add(VersionService.class);
回击;
}
@凌驾
公共集getSingleton(){
if(单例==null){
CorsFilter CorsFilter=新的CorsFilter();
corsFilter.getAllowedOriginates().add(“*”);
Singleton=新LinkedHashSet();
添加(corsFilter);
}
返回单身人士;
}
}

我最近遇到了同样的问题,并添加了对我有效的解决方案:

以下是我所做的:

  • 我创建了一个扩展javax.ws.rs.core.Application的类,并在其中添加了一个Cors过滤器
在CORS过滤器中,我添加了
corsFilter.getAllowedOriginates().add(“http://localhost:4200");

基本上,您应该添加允许跨源资源共享的URL。Ans您也可以使用
“*”
而不是任何特定的URL来允许任何URL

public class RestApplication
    extends Application
{
    private Set<Object> singletons = new HashSet<Object>();

    public MessageApplication()
    {
        singletons.add(new CalculatorService()); //CalculatorService is your specific service you want to add/use.
        CorsFilter corsFilter = new CorsFilter();
        // To allow all origins for CORS add following, otherwise add only specific urls.
        // corsFilter.getAllowedOrigins().add("*");
        System.out.println("To only allow restrcited urls ");
        corsFilter.getAllowedOrigins().add("http://localhost:4200");
        singletons = new LinkedHashSet<Object>();
        singletons.add(corsFilter);
    }

    @Override
    public Set<Object> getSingletons()
    {
        return singletons;
    }
}
公共类重新应用程序
扩展应用程序
{
private Set singleton=new HashSet();
公共消息应用程序()
{
singletons.add(new CalculatorService());//CalculatorService是您要添加/使用的特定服务。
CorsFilter CorsFilter=新的CorsFilter();
//要允许CORS的所有来源,请添加以下内容,否则仅添加特定URL。
//corsFilter.getAllowedOriginates().add(“*”);
System.out.println(“仅允许重新引用URL”);
corsFilter.getAllowedOriginates().add(“http://localhost:4200");
Singleton=新LinkedHashSet();
添加(corsFilter);
}
@凌驾
公共集getSingleton()
{
返回单身人士;
}
}
  • 这是我的web.xml:

Restful Web应用程序
轻松扫描
真的
resteasy.servlet.mapping.prefix
/休息
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
RESTEasyServlet
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
javax.ws.rs.Application
com.app.RestApplication
RESTEasyServlet
/休息/*
有些自定义更改您可能不需要或更改如下:

    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

RESTEasyServlet
/休息/*


轻松扫描
真的


resteasy.servlet.mapping.prefix
/休息
当我遇到这个问题时,最重要的代码是,我没有将扩展javax.ws.rs.Application的类(即RestApplication)添加到
resteasy servlet的init参数中


javax.ws.rs.Application
com.app.RestApplication
因此我的筛选器无法执行,因此应用程序不允许来自指定URL的COR。


注:我使用的是RestEasy版本:3.12.1。最终版

@Leo如果这解决了问题,请投票或将答案标记为正确。干杯。谢谢你的快速回复!如何实现代理?如果我在CXF中使用另一个AS(即Tomcat)而不是RESTEasy,那么它在没有代理的情况下工作。CXF完全有可能实现代理来完成类似的事情。或者,tomcat在这里有代理一个更好的解决方案是修复地址,这样您就不会进行任何跨站点脚本编写。设置代理是一种痛苦,如果做得不好,也是一个安全漏洞。我同意!但我必须这样做才能使用这种体系结构:访问Apache的客户端使用JBoss AS7(使用JAX-RS/RESTEasy)进行跨站点脚本编写。你有关于我如何实现代理的参考资料吗?等等。用户明确表示他正在使用CORS。因此,跨来源请求应该有效。您是否有在请求/响应中发送的头的示例?帮助了我。我穿的是运动衫,不是吗
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;

import org.jboss.resteasy.plugins.interceptors.CorsFilter;


@ApplicationPath("/api")
public class RestApplication extends javax.ws.rs.core.Application {
    Set<Object> singletons;

    @Override
    public Set<Class<?>> getClasses() {
        HashSet<Class<?>> clazzes = new HashSet<>();
        clazzes.add(VersionService.class);
        return clazzes;
    }

    @Override
    public Set<Object> getSingletons() {
        if (singletons == null) {
            CorsFilter corsFilter = new CorsFilter();
            corsFilter.getAllowedOrigins().add("*");

            singletons = new LinkedHashSet<Object>();
            singletons.add(corsFilter);
        }
        return singletons;
    }
}
public class RestApplication
    extends Application
{
    private Set<Object> singletons = new HashSet<Object>();

    public MessageApplication()
    {
        singletons.add(new CalculatorService()); //CalculatorService is your specific service you want to add/use.
        CorsFilter corsFilter = new CorsFilter();
        // To allow all origins for CORS add following, otherwise add only specific urls.
        // corsFilter.getAllowedOrigins().add("*");
        System.out.println("To only allow restrcited urls ");
        corsFilter.getAllowedOrigins().add("http://localhost:4200");
        singletons = new LinkedHashSet<Object>();
        singletons.add(corsFilter);
    }

    @Override
    public Set<Object> getSingletons()
    {
        return singletons;
    }
}
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Restful Web Application</display-name>

    <!-- Auto scan rest service -->
    <context-param>
        <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>
    </context-param>

    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/rest</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>resteasy-servlet</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.app.RestApplication</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

</web-app>
    <servlet-mapping>
        <servlet-name>resteasy-servlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>
    </context-param>
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/rest</param-value>
    </context-param>
   <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>com.app.RestApplication</param-value>
    </init-param>