自动在每个响应中添加标题

40

每当客户端发出对我的应用程序的rest控制器的请求时,我希望向每个响应中添加此标头“Access-Control-Allow-Origin”,“*”,以允许跨域资源共享。目前,我需要像这样手动将此标头添加到每个方法中:

HttpHeaders headers = new HttpHeaders();
headers.add("Access-Control-Allow-Origin", "*");

它可以工作,但非常令人沮丧。我在Spring文档中找到了WebContentInterceptor,它允许我们修改每个响应的标头。

它能运行, 但是非常令人沮丧。我在Spring文档中找到了WebContentInterceptor,它允许我们修改每个响应的头部。

<mvc:interceptors>
<bean id="webContentInterceptor" 
class="org.springframework.web.servlet.mvc.WebContentInterceptor">
<property name="Access-Control-Allow-Origin" value="*"/>
</bean>
</mvc:interceptors>
但当我使用时,它会抛出错误,指出未找到名称Access-Control-Allow-Origin的属性,所以是否有其他方法可以自动将标头添加到每个响应中?
更新! Spring框架4.2通过为方法或控制器本身添加@CrossOrigin注释大大简化了此过程。 https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
7个回答

59

我最近遇到了这个问题,并找到了以下解决方案。 您可以使用过滤器添加这些标头:

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;

public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
            response.addHeader("Access-Control-Allow-Origin", "*");
            if (request.getHeader("Access-Control-Request-Method") != null
                    && "OPTIONS".equals(request.getMethod())) {
                // CORS "pre-flight" request
                response.addHeader("Access-Control-Allow-Methods",
                        "GET, POST, PUT, DELETE");
                response.addHeader("Access-Control-Allow-Headers",
                        "X-Requested-With,Origin,Content-Type, Accept");
            }
            filterChain.doFilter(request, response);
    }

}

别忘了在你的Spring上下文中添加过滤器:

<bean id="corsFilter" class="my.package.CorsFilter" />

以及在web.xml中的映射:

<filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

如果想进一步控制,可以通过指定Spring配置文件来启用或禁用该过滤器,如下:

<beans profile="!cors">
    <bean id="corsFilter" class="my.package.FilterChainDoFilter" />
</beans>

<beans profile="cors">
    <bean id="corsFilter" class="my.package.CorsFilter" />
</beans>

提供类似于CorsFilter的FilterChainDoFilter,但它只在doFilterInternal(..)中执行filterChain.doFilter(request, response);


我的过滤器没有被调用 :( 我正在使用使用 Spring Security 的过滤器,我已经在 web.xml 中配置了 DelegatingFilterProxy。有什么建议吗? - bentzy
@Benny DelegatingFilterProxy只是一个包装您的过滤器的代理,因此我认为它不能被“已注册”,因为您可以拥有任意数量的代理。尝试使用正确的名称(在我的示例中为corsFilter)添加另一个代理。 - Dayde
为什么在web.xml中使用DelegatingFilterProxy?它对我没有用。只有在设置CorsFilter时才有效。 - Igorock
运行得非常好。谢谢。 - Akash Arora

15

5
如果您想为控制器设置头部,您可以使用@ModelAttribute注解。
@ModelAttribute
public void setVaryResponseHeader(HttpServletResponse response) {
    response.setHeader("Vary", "Accept");
}    

你能在这里获取HttpServletRequest吗? - alex

1
在Spring 4中,您可以使用@CrossOrigin()来解决跨域问题。
出于安全考虑,浏览器禁止对当前源以外的资源进行AJAX调用。例如,当您在一个标签页中查看银行账户时,在另一个标签页中可能会有恶意网站。来自恶意网站的脚本不应该能够使用您的凭据向银行API发出AJAX请求(从您的账户中提取资金!)。
跨域资源共享(CORS)是由大多数浏览器实现的W3C规范,它允许您以灵活的方式指定哪些跨域请求得到授权,而不是使用一些不太安全和不太强大的技巧,如IFrame或JSONP。
Spring Framework 4.2 GA提供了内置的CORS支持,为您提供了比典型的基于过滤器的解决方案更简单、更强大的配置方式。
您可以在@ RequestMapping注释的处理程序方法上添加@CrossOrigin注释,以启用CORS。默认情况下,@CrossOrigin允许所有来源和@ RequestMapping注释中指定的HTTP方法:
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin
    @RequestMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html

https://spring.io/guides/gs/rest-service-cors/

https://spring.io/blog/2015/06/08/cors-support-in-spring-framework


0

基本上,我在浏览器中遇到了一个问题,因为我的Spring服务器没有告诉浏览器该怎么做(在头部未添加“允许来源”)。

所以,在SPRING CLOUD GATEWAY中解决的问题如下:

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomGlobalFilter implements GlobalFilter {


@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

    exchange.getResponse().getHeaders().set("Access-Control-Allow-Origin", "*");

    if (exchange.getResponse().getHeaders().getAccessControlRequestMethod() != null
            && "OPTIONS".equals(exchange.getResponse().getHeaders().getAccessControlRequestMethod())) {
        // CORS "pre-flight" request
        exchange.getResponse().getHeaders().set("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE");
        exchange.getResponse().getHeaders().set("Access-Control-Allow-Headers",
                "X-Requested-With,Origin,Content-Type,Accept");
    }
    return chain.filter(exchange);
}

}


0

WebContentInterceptor没有名为Access-Control-Allow-Origin的属性,而且据我所知,它也没有公开任何设置响应头的方法。它只通过启用/禁用某些属性来设置一些与缓存相关的标头。但编写自己的拦截器(或servlet过滤器)以执行此操作非常简单。


0

我也遇到了这个问题,但我添加了这段代码后问题得到了解决。

public static HttpServletResponse getResponse(HttpServletResponse response) {
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setCharacterEncoding("UTF-8");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET");
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
    return response;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接