我开发了一组RESTful Web服务。 由于错误 No 'Access-Control-Allow-Origin' header is present on the requested resource.
,我不能从远程客户端调用这些方法。
这些服务在本地主机上运行得很完美。是否有任何服务器端的更改或配置可以解决此问题,例如启用跨域请求?
我正在使用WildFly 8,JavaEE 7。
我开发了一组RESTful Web服务。 由于错误 No 'Access-Control-Allow-Origin' header is present on the requested resource.
,我不能从远程客户端调用这些方法。
这些服务在本地主机上运行得很完美。是否有任何服务器端的更改或配置可以解决此问题,例如启用跨域请求?
我正在使用WildFly 8,JavaEE 7。
我也想知道同样的问题,所以经过一番研究,我发现最简单的方法就是使用JAX-RS ContainerResponseFilter
来添加相关的CORS头部。这样做就不需要用CXF替换整个Web服务堆栈(Wildfly在某种形式上使用CXF,但看起来它仅仅用于JAX-WS而非JAX-RS)。
无论如何,如果您使用此过滤器,则会将标头添加到每个REST Web服务中。
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运行时使用该过滤器,没有这个注解就不会发生任何事情。
我从Jersey示例中学习到了使用ContainerResponseFilter
的方法。
String origin = requestContext.getHeaderString("origin");
,然后(当 origin !== null
时),使用该来源代替通配符:cres.getHeaders().add("Access-Control-Allow-Origin", origin);
。如果您的 API 使用 cookie 进行身份验证(例如在使用容器管理的身份验证时),请在设置 CORS 标头之前将来源与允许的来源白名单进行比较。 - Stijn de Witt我遇到了类似的问题,并尝试使用 @Alex Petty 的解决方案,但除了需要在我的类中设置每个 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标头,从而捕获以下所有类型的端点:
@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();
}
只有在这样做之后,我才能够正确地使用我的JAX-RS API端点来自其他域或主机的jQuery Ajax客户端。
@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();
}
我在Wildfly上配置跨域资源共享(CORS) API时,使用了这个库,运气不错:
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.1</version>
</dependency>
安装非常简单。只需将上述依赖项添加到您的pom中,然后将以下配置添加到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>
如果你更喜欢的话,也可以使用属性文件来配置它。这个库运行良好,提供了很多配置灵活性!
The 'Access-Control-Allow-Origin' header contains multiple values 'http://127.0.0.1, *', but only one is allowed.
有什么办法可以更改web.xml使其正确吗? - Ayyoub其他答案对我都无效,但这个有效:
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;
}
}
解决方案是在响应中添加一些头信息。在Spring或Spring Boot中有注释,但在旧系统中可能没有注释。您可以通过添加过滤器来解决。
package com.koushik.restapis.intercepter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class RestCorsFilter implements Filter {
@Override
public void destroy() {
enter code here
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
resp.addHeader("Access-Control-Allow-Origin", "*");
resp.addHeader("Access-Control-Allow-Headers", "*");
resp.addHeader("Access-Control-Allow-Methods", "*");
chain.doFilter(request, resp);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
<filter>
<filter-name>RestCorsFilter</filter-name>
<filter-class>com.koushik.restapis.RestCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RestCorsFilter</filter-name>
<url-pattern>/apis/*</url-pattern>
</filter-mapping>
仅仅是为了补充其他回答的内容。 允许使用 * 是有一定危险的。 可以做的是配置一个允许来源的数据库(可以是文件)
然后当请求到达时,您可以执行以下操作:
// 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");
}
@Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
containerResponseContext.getHeaders().add(
"Access-Control-Allow-Origin", "*");
containerResponseContext.getHeaders().add(
"Access-Control-Allow-Credentials", "true");
containerResponseContext.getHeaders().add(
"Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
containerResponseContext.getHeaders().add(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
由于您正在使用JAX-RS,因此您的应用程序类扩展了Applicaton类,您只需要覆盖其getSingletons方法:
@Override
public Set<Object> getSingletons() {
return mySingletons();
}
你的单例模式可以如下:
public static Set<Object> mySingletons() {
Set<Object> singletons = new HashSet<>();
singletons.add(new MyFilter());
return singletons;
}
我尝试了上面的答案并在web.xml等方面进行了更改,但它们都没有起作用,所以我想出了这个解决方案,尝试了所有可能的方法。
@Joel Pearson的答案很有帮助,但对于像我这样对JAX-RS不熟悉且通过配置web.xml在Tomcat上运行服务的人,在创建类和将其放置在项目中的任何位置时都应该小心。查看您在下指定的Jersey包,并在其中创建此过滤器类。这样我就解决了问题。