使用 JAX-RS/RESTEasy 实现 CORS 的 Ajax 请求
Posted
技术标签:
【中文标题】使用 JAX-RS/RESTEasy 实现 CORS 的 Ajax 请求【英文标题】:Ajax request with JAX-RS/RESTEasy implementing CORS 【发布时间】:2013-01-13 09:14:26 【问题描述】:我有两台服务器(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();
web.xml 和 beans.xml 是空文件。 当我访问 MyIP:8080 (Apache) 时,我收到错误消息:
XMLHttpRequest cannot load http://localhost:9080/myproject/services/mobile/list?_=1359480354190. Origin http://MyIP:8080 is not allowed by Access-Control-Allow-Origin.
有人知道怎么回事吗?
【问题讨论】:
this article 帮助了我。不过我用的是球衣。 【参考方案1】:我最近遇到了同样的问题并添加了对我有用的解决方案:
以下是我所做的:
我创建了一个扩展 javax.ws.rs.core.Application 的类,并向其中添加了一个 Cors 过滤器。在 CORS 过滤器中,我添加了 corsFilter.getAllowedOrigins().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;
这是我的 web.xml:
<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>
最重要的代码当我遇到这个问题时,我没有添加我的扩展 javax.ws.rs.Application 的类,即 RestApplication 到 @987654328 的 init-param @
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.app.RestApplication</param-value>
</init-param>
因此我的过滤器无法执行,因此应用程序不允许来自指定 URL 的 CORS。
PS:我使用的是 RestEasy 版本:3.12.1.Final
【讨论】:
【参考方案2】:最新的resteasy(3.0.9-Final)包含一个实用程序类org.jboss.resteasy.plugins.interceptors.CorsFilter
。
您可以将 CorsFilter 对象添加到应用程序的单例中 对象集,或将其添加到 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;
【讨论】:
对我不起作用。当我将 getSingletons() 方法添加到我的应用程序时,我无法调用我的任何休息端点,它们根本停止工作。删除 getSingletons 方法后,我可以再次调用端点。 这是我在之前评论中描述的问题的解决方案:***.com/questions/29388937/… 我遇到了同样的问题,Tomcat 忽略了带注释的 CorsFilter 类,我必须在应用程序中添加 cors 过滤器,然后像您一样将其添加到单例中。谢谢【参考方案3】:好吧,我已经实现了一个小解决方案,首先我在我的项目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();
在Web.xml文件中,我添加了
<context-param>
<param-name>resteasy.providers</param-name>
<param-value><package>.CorsInterceptor</param-value>
</context-param>
包:类的统一。
请求我使用过的 JQuery。
$.ajax(
type: 'GET',
dataType: "json",
crossDomain : true,
cache:false,
url: "http://localhost:12005/ProyectoWebServices/ws/servicioTest",
success: function (responseData, textStatus, jqXHR)
alert("Successfull: "+responseData);
,
error: function (responseData, textStatus, errorThrown)
alert("Failed: "+responseData);
);
对我来说效果很好。希望对你有帮助。
【讨论】:
【参考方案4】:听起来这个问题与https://issues.jboss.org/browse/RESTEASY-878 有关。您可能无法使用MessageBodyWriterInterceptor
捕获 CORS 预检请求。尝试改用 servlet 过滤器 (@WebFilter
)。
【讨论】:
【参考方案5】:您遇到的问题是您正在尝试执行跨站点脚本。您在http://MyIP:8080
访问了该页面,因此浏览器阻止您访问该域之外的资源。这是非常特定于浏览器的,基于浏览器的解决方法都会有所不同(您可以在 Chrome 中全局禁用安全性,并在 IE 中基于每个站点禁用安全性)。
如果您将页面加载为http://localhost:8080
,那么它应该允许您访问查询。或者,您可以实现一个代理来转发请求。
【讨论】:
@Leo 如果可以解决问题,请投票或将答案标记为正确。干杯。 感谢马克的快速回复!如何实现代理?如果我使用另一个带有 CXF 而不是 RESTEasy 的 AS(例如 Tomcat),它可以在没有代理的情况下工作。 CXF 完全有可能实现一个代理来做这样的事情。或者,tomcat 在这里有代理wiki.apache.org/tomcat/ServletProxy 更好的解决方案是修复地址,这样您就不会执行任何跨站点脚本。设置代理很麻烦,如果做得不好也会出现安全漏洞。 我同意!但我必须这样做才能使用该架构:访问 Apache 的客户端使用 JBoss AS7 执行跨站点脚本(使用 JAX-RS/RESTEasy)。你有一些关于我如何实现代理的参考吗? 等一下。用户明确表示他正在使用 CORS。所以跨域请求应该可以工作。您是否有在请求/响应中发送的标头示例?以上是关于使用 JAX-RS/RESTEasy 实现 CORS 的 Ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章
使用JAX-RS resteasy和ContainerRequestFilter / ContainerResponseFilter记录请求
将 Web 代理与 Java 8 JAX-RS RESTEasy 客户端一起使用
如何将对象从 ContainerRequestFilter 传递到资源
R使用笔记:相关系数:cor.test();corr.test();rcorr()
R语言使用cov函数计算矩阵或者dataframe数据变量之间的协方差cor函数计算相关性cor函数通过method参数指定相关性相关性计算方法Pearson,Spearman, Kendall
R语言使用cov函数计算矩阵或者dataframe数据变量之间的协方差cor函数计算相关性cor函数通过method参数指定相关性相关性计算方法Pearson,Spearman, Kendall