一个简洁的博客网站:http://lss-coding.top,欢迎大家来访
学习娱乐导航页:http://miss123.top/
1. 什么是跨域?
当一个请求 URL 的协议、域名、端口号三者之间任意一个与当前页面 URL 不同即为跨域。
当前页面 URL | 被请求页面 URL | 是否跨域 | 原因 |
---|---|---|---|
http://www.myweb.com/ | http://www.myweb.com/index.html | 否 | 同源(协议、域名、端口号相同) |
http://www.myweb.com/ | https://www.myweb.com/index.html | 是 | 协议不同(http/https) |
http://www.myweb.com/ | http://www.taobao.com/ | 是 | 主域名不同(myweb/taobao) |
http://www.myweb.com/ | http://blog.taobao.com/ | 是 | 子域名不同(www/blog) |
http://www.myweb.com:8001/ | http://www.myweb.com:8002/ | 是 | 端口号不同(8001/8002) |
2. 跨域产生的原因?
浏览器的同源策略限制
同源策略:URL 是由协议、域名、端口号和路径组成的,如果两个 URL 的协议、域名和端口号相同,则表示这两个 URL 是同源的。浏览器的同源策略,从一个域上加载的脚本不允许访问另外一个域的文档属性,是浏览器上为安全性考虑实施的非常重要的安全策略。
同源策略(Same Origin Policy)是一种约定,是浏览器核心也是最基本的安全功能,它会阻止一个域的 js 脚本和另外一个域的内容进行交互,如果缺少了同源策略,浏览器很容易受到 XSS、CSRF 等攻击,浏览器的正常功能都会受到影响。所谓同源(即在同一个域),就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)
简答说 A 应用只能访问 A 应用后台传来的数据,B应用只能访问 B 应用后台传来的数据,如果 A 应用用 ajax 获取数据时的 URL 地址中 协议、端口、域名 其中有一个和 B 应用对应的话(即请求 URL 与 A 应用的 URL 不同),则是 A 应用跨域了想获取 B 应用的数据,是不允许的。
例如:在一个恶意网站的页面通过 iframe 嵌入了一个银行的登录页面(恶意网站和登录页面是不同源的),如果没有同源限制,恶意网页上的 javascript 脚本就可以在用户登录银行账号的时候获取用户名和密码。
非同源限制:
浏览器为了安全,限制了一些请求无法访问非同源 URL
- 无法读取非同源网页的 Cookie、LoacalStorage 和 IndexedDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发送 ajax 请求
3. SpringBoot 解决跨域
以下三种方法都可以解决跨域的问题,三种方法不能同时使用,否则会出现问题,所以只能选定一种方法来解决跨域问题。
其实无论哪种方案,最终目的都是修改响应头,向响应头中添加浏览器所要求的数据,进而实现跨域。
3.1 使用注解 @CrossOrigin(局部跨域)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
@Deprecated // 不推荐使用
String[] DEFAULT_ORIGINS = {"*"};
/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
@Deprecated // 不推荐使用
String[] DEFAULT_ALLOWED_HEADERS = {"*"};
/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
@Deprecated // 不推荐使用
boolean DEFAULT_ALLOW_CREDENTIALS = false;
/** @deprecated as of Spring 5.0, in favor of {@link CorsConfiguration#applyPermitDefaultValues} */
@Deprecated // 不推荐使用
long DEFAULT_MAX_AGE = 1800;
/**
* Alias for {@link #origins}.
*/
// 这里 value 和下面的 origins 是一样的
// 允许来源域名的列表,例如 'www.taobao.com',匹配的域名是跨域预请求 Response 头中的 'Access-Control-Allow_origin'
// 字段值,不设置确切值时默认支持所有域名跨域访问。
@AliasFor("origins")
String[] value() default {};
/**
* The list of allowed origins that be specific origins, e.g.
* {@code "https://domain1.com"}, or {@code "*"} for all origins.
* <p>A matched origin is listed in the {@code Access-Control-Allow-Origin}
* response header of preflight actual CORS requests.
* <p>By default all origins are allowed.
* <p><strong>Note:</strong> CORS checks use values from "Forwarded"
* (<a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a>),
* "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" headers,
* if present, in order to reflect the client-originated address.
* Consider using the {@code ForwardedHeaderFilter} in order to choose from a
* central place whether to extract and use, or to discard such headers.
* See the Spring Framework reference for more on this filter.
* @see #value
*/
@AliasFor("value")
String[] origins() default {};
/**
* The list of request headers that are permitted in actual requests,
* possibly {@code "*"} to allow all headers.
* <p>Allowed headers are listed in the {@code Access-Control-Allow-Headers}
* response header of preflight requests.
* <p>A header name is not required to be listed if it is one of:
* {@code Cache-Control}, {@code Content-Language}, {@code Expires},
* {@code Last-Modified}, or {@code Pragma} as per the CORS spec.
* <p>By default all requested headers are allowed.
*/
// 跨域请求中允许的请求头中的字段类型,该值对应跨域预请求 Response 头中的 'Access-Control-Allow-Headers' 字段值
// 不设置确切值默认支持所有的 header 字段(Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、Pragma)跨域访问
String[] allowedHeaders() default {};
/**
* The List of response headers that the user-agent will allow the client
* to access on an actual response, other than "simple" headers, i.e.
* {@code Cache-Control}, {@code Content-Language}, {@code Content-Type},
* {@code Expires}, {@code Last-Modified}, or {@code Pragma},
* <p>Exposed headers are listed in the {@code Access-Control-Expose-Headers}
* response header of actual CORS requests.
* <p>By default no headers are listed as exposed.
*/
// 跨域请求头中允许携带的除 Cache-Controller、Content-Language、Content-Type、Expires、Last-Modified、
// Pragma 这六个基本字段之外的其他字段信息、对应的跨域请求 Response 头中的 'Access-control-Expose-Headers'字段值
String[] exposedHeaders() default {};
/**
* The list of supported HTTP request methods.
* <p>By default the supported methods are the same as the ones to which a
* controller method is mapped.
*/
// 跨域 HTTP 请求中支持的 HTTP 请求类型(GET、POST...),不指定确切值时默认与 Controller 方法中的 methods 字段保持一致
RequestMethod[] methods() default {};
/**
* Whether the browser should send credentials, such as cookies along with
* cross domain requests, to the annotated endpoint. The configured value is
* set on the {@code Access-Control-Allow-Credentials} response header of
* preflight requests.
* <p><strong>NOTE:</strong> Be aware that this option establishes a high
* level of trust with the configured domains and also increases the surface
* attack of the web application by exposing sensitive user-specific
* information such as cookies and CSRF tokens.
* <p>By default this is not set in which case the
* {@code Access-Control-Allow-Credentials} header is also not set and
* credentials are therefore not allowed.
*/
// 该值对应的是跨域请求 Response 头中的 'Access-Control-Allow-Credentials' 字段值。
// 浏览器是否将本域名下的 cookie 信息携带至跨域服务器中。默认携带至跨域服务器中,但实现 cookie
// 共享还需要前端在 ajax 请求中打开 withCredentials 属性
String allowCredentials() default "";
/**
* The maximum age (in seconds) of the cache duration for preflight responses.
* <p>This property controls the value of the {@code Access-Control-Max-Age}
* response header of preflight requests.
* <p>Setting this to a reasonable value can reduce the number of preflight
* request/response interactions required by the browser.
* A negative value means <em>undefined</em>.
* <p>By default this is set to {@code 1800} seconds (30 minutes).
*/
// 该值对应的是跨域请求 Response 头中的 'Access-Control-Max-Age' 字段值,表示预检请求响应的缓存持续的最大时间,
// 目的是减少浏览器预检请求/响应交互的数量。默认值 1800s。设置了该值后,浏览器将在设置值的时间段内对该跨域请求不再发起预请求
long maxAge() default -1;
}
- 在控制器(类上)使用注解解决跨域,表示该类下的所有方法都允许跨域
@Controller
@CrossOrigin(origins = "*", methods = {RequestMethod.GET,RequestMethod.POST})
public class SystemController extends BaseController {
@GetMapping("/test")
@ResponseBody
public String test() {
return "test @CrossOrigin";
}
}
- 在方法上使用注解解决跨域,表示只有该方法允许跨域
@Controller
public class SystemController extends BaseController {
// 设置只能某些地址访问
@CrossOrigin(origins = "http://localhost:9999")
@GetMapping("/test")
@ResponseBody
public String test() {
return "test @CrossOrigin";
}
}
3.2 配置 CorsFilter(全局跨域)
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 WebGlobalConfig {
@Bean
public CorsFilter corsFilter() {
// 1. 创建 CorsConfiguration 对象后添加配置
CorsConfiguration configuration = new CorsConfiguration();
// 设置放行那些域
configuration.addAllowedOrigin("*");
// 放行那些原始请求头部信息
configuration.addAllowedHeader("*");
// 暴露那些头部信息
configuration.addExposedHeader("*");
// 放行那些请求方式
configuration.addAllowedMethod("GET"); // get
configuration.addAllowedMethod("POST"); // post
configuration.addAllowedMethod("PUT"); // put
configuration.addAllowedMethod("DELETE"); // delete
// configuration.addAllowedMethod("*"); // 放行全部请求
// 是否发送 Cookie
configuration.setAllowCredentials(true);
// 2. 添加映射路径
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
// 3. 返回 CorsFilter
return new CorsFilter(source);
}
}
3.3 重写 WebMvcConfigurer 的 addCorsMappings 方法(全局跨域)
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 添加映射路径
registry.addMapping("/**")
// 是否发送 Cookie
.allowCredentials(true)
// 设置放行那些原始域
.allowedOrigins("*")
// 放行那些请求方式
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
// .allowedMethods("*") // 放行全部
// 放行那些原始请求头部信息
.allowedHeaders("*")
// 暴露那些原始请求头部信息
.exposedHeaders("*");
}
}
**学习参考地址:**https://www.cnblogs.com/antLaddie/p/14751540.html