跨域请求
域 的定义:协议 + 域名 + 端口。
三者完全相同则为同域,反之有其一不同均为不同域,
当前发起请求的 域 和请求指向的 域 属于不同域时,该次请求称之为跨域请求。
A应用只能访问 A 应用后台传来数据,B 应用只能访问 B 应用后台传来的数据;
如果 A 应用用 Ajax 获取数据时的 URL 地址中的协议、端口、域名其中有一个和 B 应用对应的话,则是 A 应用跨域获取 B 应用数据,是不允许的。
同源策略
同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。
所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
跨域的几种情况
- 同一域名下允许通信(未指定端口协议)
- 同一域名下不同文件夹允许通信
- 同一域名不同端口不允许通信
- 同一域名不同协议不允许通信
- 域名和域名对应IP不允许通信
- 主域名相同,子域名不同不允许通信
- 同一域名,不同二级域名不允许通信
- 不同域名不允许通信
当前页面 URL | 被请求URL | 是否跨越 | 原因 |
---|---|---|---|
http://www.baidu.com | http://www.baidu.com/java.html | 否 | 同源(协议,域名,端口均相同) |
http://www.baidu.com | https://www.baidu.com/java.html | 跨越 | 协议不同(http,https) |
http://www.baidu.com | http://www.google.com | 跨越 | 主域名不同(baidu,google) |
http://www.baidu.com | http://zhidao.baidu.com | 跨越 | 子域名不同(www,zhidao) |
http://www.baidu.com:8080 | http://www.baidu.com:90 | 跨越 | 端口不同(80,90)) |
1. 定义 CorsFilter (全局跨域)
在配置类中,返回一个 新的 CorsFIlter Bean ,并添加映射路径和具体的CORS配置路径。
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1. 添加 CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否发送 Cookie
config.setAllowCredentials(true);
//放行哪些请求方式
config.addAllowedMethod("*");
//放行哪些原始请求头部信息
config.addAllowedHeader("*");
//暴露哪些头部信息
config.addExposedHeader("*");
//2. 添加映射路径
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**",config);
//3. 返回新的CorsFilter
return new CorsFilter(corsConfigurationSource);
}
}
2. 重写 WebMvcConfigurer (全局跨域)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//是否发送Cookie
.allowCredentials(true)
//放行哪些原始域
.allowedOrigins("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
3. 使用自定义 Filter (全局跨域)
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
}
4. 使用注解 (局部跨域)
在 crontaller 类或者方法上使用注解 @CrossOrigin 表示该类的所有方法允许跨域。
# 在类上面设置
@RestController
@CrossOrigin(origins = "*")
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello world";
}
}
# 在方法上面设置
@RequestMapping("/hello")
@CrossOrigin(origins = "*")
//@CrossOrigin(value = "http://localhost:8081") //指定具体ip允许跨域
public String hello() {
return "hello world";
}