一、跨域相关概念简介
1、同源策略[same origin policy]:
它是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源, 同源策略是浏览器安全的基石。同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
这里为了方便大伙清晰地理解同源策略的概念,截取百度百科的简介:
- 同源策略,它是由Netscape提出的一个著名的安全策略。
- 现在所有支持JavaScript 的浏览器都会使用这个策略。
- 所谓同源是指,域名,协议,端口均相同。
- 当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面
- 当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。
- 如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
- 同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
2、JSONP:
我们在实际开发时,或多或少也会经常遇到跨域的需求,而传统的跨域方案一般采用JSONP,但是JSONP只支持get请求,不支持post、put、delete等其他请求,有局限性,并且现在提供 RESTful 风格的API,除了 get 请求,put、post、delete也会经常使用,而 JSONP 只支持 get请求,这在 RESTful 应用中就略显吃力了。
3、CORS:
因此,我们这里引进一个CORS(跨域资源共享)的概念:CORS,全称Cross-Origin Resource Sharing ,它是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。
CORS是一个W3C标准,是一份浏览器技术的规范,提供了web服务从不同网域传来沙盒脚本的方法,它允许浏览器向跨域服务器发送Ajax请求,打破了Ajax只能访问本站内的资源限制,从而避开浏览器的同源策略,这是JSONP模式的现代版。
在传统的Spring框架中,有提供了CORS的解决方案,这里只介绍SpringBoot中实现CORS跨域的配置方案。
二、SpringBoot实现CORS示例
1、搭建SpringBoot应用
使用开发工具IDEA或Eclipse等,分别新建两个SpringBoot项目:
- 应用一名称:springboot-cors1
- 应用二名称:springboot-cors2
我使用的是2.1.7.RELEASE版本 ,添加相关依赖即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、配置应用端口
两个应用,分别在application.properties中配置不同的端口:
-
server.port=8081
-
server.port=8082
3、提供HTTP接口方法
在springboot-cors1 应用 新增一个控制器类,并提供一个get请求方法:
@RestController
public class IndexController {
@GetMapping("/test")
public String corsTest(){
return "hello,CORS !";
}
}
4、新增测试
在 springboot-cors2 新增一个index.html ,提供一个按钮,发送get请求跳转访问 应用一 springboot-cors1
分别启动两个应用,访问 localhost:8082 ,点击get按钮,从而8082跨域请求8081接口,由于同源安全策略,请求被限制,打开浏览器调试模式,看到控制台报错如下:
5、添加CORS配置
5.1 对单个接口方法配置CORS
在springboot-cors1 的IndexController中corsTest()方法上增加注解,允许来自http://localhost/8082的应用请求该接口方法,如下:
重启springboot-cors1,再次访问应用二: localhost:8082 ,点击get按钮,这次便会成功跨域请求到应用一的接口内容:
点进 CrossOrigin 注解,可以看到该注解也可以放在类上,即应用于该类下的所有接口方法,都允许被跨域请求配置中的URL
5.2 对某个Controller下的所有接口方法配置CORS
配置在类上,就不用每个接口方法都设置:
但是,这样还是不够方便,假如我有很多接口需要允许跨域请求,岂不是每个controller类上都要配置该注解。
5.3 配置全局的CORS
方法(1)添加配置类:
package com.stwen.cors.config;
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;
/**
* @description: cors过滤器配置
* @author: stwen_gan
* @date: 2019/08/08
**/
@Configuration
public class CorsFilterConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
//若要允许被所有网域请求,可以配置*
corsConfiguration.addAllowedOrigin("http://localhost:8082");
corsConfiguration.addAllowedHeader("*");
//允许跨域请求的方法类型:GET、POST、PUT、DELETE 等
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
方法(2)添加配置类:
新建一个WebMvcConfig配置类 ,继承WebMvcConfigurerAdapter (SpringBoot 1.x 版本),并重写addCorsMappings方法。
package com.stwen.cors.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @description:
* @author: stwen_gan
* @date: 2019/08/08
**/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//允许跨域请求的方法类型:GET、POST、PUT、DELETE 等
.allowedMethods("*")
//若要允许被所有网域请求,可以配置*
.allowedOrigins("http://localhost:8082")
.allowedHeaders("*");
super.addCorsMappings(registry);
}
}
【推荐】如果是 Springboot2.0 以上,已经抛弃WebMvcConfigurerAdapter ,建议使用WebMvcConfigurationSupport,如下:
package com.stwen.cors.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/**
* @description:
* @author: stwen_gan
* @date: 2019/08/08
**/
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//若要允许被所有网域请求,可以配置*
.allowedOrigins("http://localhost:8082")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
//预检请求--最大时间
.maxAge(3600)
.allowedHeaders("*");
super.addCorsMappings(registry);
}
}
配置的详细信息说明如下:
- addMapping:配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径。
- allowedMethods:允许什么请求方法类型,可以访问该跨域资源服务器,如:POST、GET、PUT、DELETE等。
- allowedOrigins:允许什么请求域名访问我们的跨域资源,可以固定单条或者多条内容,如:“http://localhost:8082”,只有该域名可以访问我们的跨域资源。若要允许被所有网域请求,可以配置* 。
- allowedHeaders:允许什么的请求header访问,可以自定义设置任意请求头信息。
- maxAge:预检请求--最大时间。
方法(3)使用Filter方法:
需要在启动类加上@ServletComponentScan注解
@WebFilter(urlPatterns = "*")
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json; charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Methods", "*");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
httpResponse.setHeader("Access-Control-Expose-Headers", "*");
filterChain.doFilter(httpRequest, httpResponse);
}
@Override
public void destroy() {
}
}
6、PUT跨域请求
CORS也有一些限制,两种模型可以实现:
(1)简单模型
支持get/post/put/delete请求,例如返回Access-Control-Allow-Origin:*,但是不允许自定义header且会忽略cookies,且post数据格式有限制,只支持‘text/plain','application/x-www-urlencoded'and'multipart/form-data',其中’text/plain'默认支持,后面两种需要下面的预检请求和服务器协商。
(2)协商模型/预检请求(Preflighted Request)
举例:浏览器发出PUT请求,OPTION请求返回Access-Control-Allow-Origin:*,Access-Control-Allow-Methods:’PUT’,服务器同意所有域的PUT请求,浏览器收到并继续发出真正的PUT请求,服务器响应并再次返回Access-Control-Allow-Origin:*,允许浏览器的脚本执行服务器返回的数据。
在springboot-cors2 的index.html 增加一个put请求按钮:
在springboot-cors1 增加put接口方法:
分别启动两个应用,测试访问:localhost:8082
第一次跨域请求时,会先预检,先看第一个test2,预检请求是否支持,在maxAge 时间内,不用再次发起预检:
第二个,真正发起请求,获取响应
需要源码的,请下方评论,看到会发你。
本文来自:CSDN 作者:stwen_gan https://blog.csdn.net/a1036645146/article/details/98843846
转载请注明出处,谢谢。
参考:
https://mp.weixin.qq.com/s/GcMuJ23WVvo2s_6LSgR4fA
https://blog.csdn.net/lizc_lizc/article/details/81155895
https://blog.csdn.net/yft_android/article/details/80307672
https://baike.baidu.com/item/CORS/16411212