跨域配置(SpringBoot、Nginx)
什么是跨域?
简单而言,跨域请求就是当一台服务器资源从另一台服务器(不同 的域名或者端口)请求一个资源或者接口,就会发起一个跨域 HTTP 请求。举个简单的例子,从 http://www.baidu.com ,发送一个 Ajax 请求,请求地址是 http://www.taobao.com 下面的一个接口,这就是发起了一个跨域请求,在不做任何处理的情况下,显然当前跨域请求是无法被成功请求,因为浏览器基于同源策略会对跨域请求做一定的限制。
产生跨域问题的条件
例如: http://127.0.0.1:8080
当协议、IP、端口三部分中有任意一个不同时,即为跨域。
解决方案
通过设置Access-Control-Allow-Origin来实现跨域访问。
1. 使用Filter过滤器
使用Filter过滤器来过滤服务请求,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许跨域的源地址
// 在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
config.addAllowedOrigin("*");
//config.allowedOriginPatterns("*");
// 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
//config.setAllowCredentials(true);
// 允许跨域的头部
config.addAllowedHeader("*");
// 允许跨域的方法
config.addAllowedMethod("*");
// 当前跨域请求最大有效时长,单位:秒
config.setMaxAge(1800L);
// 跨域路径配置
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
或者
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter
public class CorsFilter implements Filter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 允许跨域的源地址
response.setHeader("Access-Control-Allow-Origin", "*");
// 允许跨域的头部
response.setHeader("Access-Control-Allow-Methods", "*");
// 允许跨域的方法
response.setHeader("Access-Control-Allow-Headers", "*");
// 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
response.setHeader("Access-Control-Allow-Credentials", "true");
// 当前跨域请求最大有效时长,单位:秒
response.setHeader("Access-Control-Max-Age", "1800");
filterChain.doFilter(request, response);
}
}
2. 使用FilterRegistrationBean并且设置过滤器执行顺序
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistrationBean(){
CorsConfiguration config = new CorsConfiguration();
// 允许跨域的源地址
// 在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
config.addAllowedOrigin("*");
//config.allowedOriginPatterns("*");
// 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
//config.setAllowCredentials(true);
// 允许跨域的头部
config.addAllowedHeader("*");
// 允许跨域的方法
config.addAllowedMethod("*");
// 当前跨域请求最大有效时长,单位:秒
config.setMaxAge(1800L);
// 跨域路径配置
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CorsFilter(source));
// 设置执行顺序,数字越小越先执行
bean.setOrder(0);
return bean;
}
}
3. 使用 @CrossOrigin 注解
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
// @CrossOrigin
public class HelloController {
@CrossOrigin
@GetMapping("/hello")
public String hello() {
return "success";
}
@GetMapping("/test")
public String test() {
return "failure";
}
}
4. 实现 WebMvcConfigurer,重写 addCorsMappings 方法
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
CorsRegistration cors = registry.addMapping("/**");
// 允许跨域的源地址
// 在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
cors.allowedOrigins("*");
//cors.allowedOriginPatterns("*");
// 允许用户凭证跨域(cookie、HTTP认证及客户端SSL证明等)
cors.allowCredentials(true);
// 设置 header 能携带的信息
cors.allowedHeaders("*");
// 支持跨域的请求方法
cors.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS");
// 设置跨域过期时间,单位为秒
cors.maxAge(3600);
}
}
5. 使用Nginx配置(代理)
location / {
#支持跨域访问
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers X-Requested-With,Authorization,Content-Type,Accept,Origin;
add_header Access-Control-Expose-Headers Content-Length,Content-Range;
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://127.0.0.1:8080/;
proxy_redirect default;
}
跨域测试
打开浏览器并打开任意第三方网页,F12打开浏览器开发者工具,根据实际需要测试的请求地址,输入如下代码:
var x = new XMLHttpRequest();
x.open('GET','http://127.0.0.1:8080/test');
x.send(null);
x.onload = function(e) {
var x = e.target;
console.log(x.responseText);
}