如何在JAX-RS Web服务上启用跨域请求?
我开发了一套宁静的networking服务。 由于错误, No 'Access-Control-Allow-Origin' header is present on the requested resource.
从远程客户端调用这些方法中的任何一个No 'Access-Control-Allow-Origin' header is present on the requested resource.
这些服务在localhost上完美运行。 是否有任何更改或configuration在服务器端来解决问题。 即启用跨域请求。
我正在使用WildFly 8,JavaEE 7
我想知道同样的事情,所以经过一番研究,我发现最简单的方法就是使用JAX-RS ContainerResponseFilter
来添加相关的CORS头文件。 这样你就不需要用CXF来replace整个Web服务栈(Wildfly使用CXF是某种forms,但是它看起来并不像JAX-RS使用它,也许只有JAX-WS)。
无论你使用这个filter,它都会把标题添加到每个REST webservice。
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"); } }
然后当我用curltesting时,响应有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运行时使用filter,没有注释没有任何反应。
我想到了使用Jersey例子中的ContainerResponseFilter
的想法。
我遇到了一个类似的问题,并试图使用@Alex Petty的解决scheme ,但除了必须在我的类中的每个JAX-RS端点上设置CORS头之外,如下所示:
@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
端点,它会返回类中任何其他OPTIONS
请求的CORS头文件,从而捕获所有types的端点:
@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(); }
只有这样做后,才能正确使用来自其他域或主机上的Jquery Ajax客户端的JAX-RS API端点。
我发现了一个更简单(RestEasy特定)的方式来启用Wildfly上的CORS,而不使用filter,并且可以在资源级别控制API响应头configuration。
例如:
@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(); }
我有幸使用这个lib为我的API(Wildfly)configuration了跨源资源共享(CORS):
<dependency> <groupId>com.thetransactioncompany</groupId> <artifactId>cors-filter</artifactId> <version>2.1</version> </dependency>
这是很容易安装。 只需将上面的依赖项添加到您的pom中,然后将以下configuration添加到web.xml文件的webapp部分即可。
<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>
如果您愿意,也可以使用属性文件进行configuration。 这个库就像一个魅力,给你很多configuration的灵活性!
没有其他的答案为我工作,但这样做:
import javax.ws.rs.core.Response;
然后将服务方法的返回types更改为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; } }
只是为了添加其他答案。 允许*有点危险。 可以做什么是configuration一个允许的来源数据库(它可以是一个文件)
然后当请求到达时,你可以做:
// 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"); }
那样你就不会容许每个人。