• SpringBoot 中到底如何解决跨域问题?


    大家好,我是路人,这是SpringMVC系列第31篇。

    今天又给大家带来了一个很重要的知识点:SpringMVC中如何处理跨域问题,本文的内容同样适合于SpringBoot

    1、跨域访问报错

    当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。

    出于安全原因,浏览器禁止Ajax调用驻留在当前原点之外的资源,比如从a.com发送一个ajax请求到b.com,则浏览器控制台会报跨域访问错误。

    如下图,从http://localhost:63342/站点页面中向ttp://localhost:8080/chat21/cors/test2发送一个ajax请求,则出现了红色的错误信息,错误中包含了Access-Controll-Allow-Origin这样字样的错误,以后看到这个的时候,大家就要一眼看出来这是跨域问题。

    f846ad9407f8ca3f4f5a81099a4d858e.png

    2、同源定义

    同源策略是浏览器的一个重要的安全策略,它用于限制一个源的文档或其加载的脚本如何与另外一个源进行交互,它能够隔绝恶意文档,减少被攻击的媒介。

    如果两个URL的协议主机名端口号都是相同的,那么这两个URL就是同源的,否则不同源,不同源的访问就会出现跨域问题,就会出现上面的错误。

    下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:

    URL

    结果

    原因

    http://store.company.com/dir2/other.html

    同源

    只有路径不同

    https://store.company.com/secure.html

    非同源

    协议不同

    http://store.company.com:81/dir/etc.html

    非同源

    端口号不同

    http://news.company.com/dir/other.html

    非同源

    主机名不同

    也就是说当在http://store.company.com/dir/page.html这个网站中向https://store.company.comhttp://store.company.com:81http://news.company.com三个地址发起AXJX请求都会失败并且会报跨域的错误。这就是浏览器的同源策略,只能访问同源的数据。

    3、跨域问题如何解决?

    跨域问题需要使用CORS来解决,请求端和后端接口需要遵循CORS规则来通信,便可解决跨域访问的问题。

    CORS全称Cross-Origin Resource Sharing, 即跨域资源共享,是一个由一系列HTTP头组成的系统,这些HTTP头决定浏览器是否阻止前端javascript代码获取跨域请求的响应。为什么需要CORS ?这是因为浏览器存在同源安全策略,当我们在当前域请求另外一个域的资源时,浏览器默认会阻止脚本读取它的响应,这时CORS就有了用武之地。

    跨源资源共享(CORS)是由大多数浏览器实现的W3C规范,允许您灵活地指定什么样的跨域请求被授权,而不是使用一些不太安全和不太强大的策略,如IFRAME或JSONP等。

    4、CORS原理

    CORS的原理:简单点说,就是在请求头或响应头中添加了一些配置,通过这些配置来便可轻松解决跨域问题。

    想详细了解CORS原理的,建议先阅读下面2篇文章,然后再继续向下看,否则,最后你知道SpringMVC是如何解决的,但是不知道本质的原理是什么。

    • CORS通信:http://itsoku.com/article/197

    • 浏览器安全策略 & CORS:http://itsoku.com/article/198

    5、SpringMVC中如何解决跨域问题?

    SpringMVC内部提供了跨域问题的解决方案,只需要做一些简单的配置,而接口基本上不用做任何修改,便可解决跨域问题。

    SpringMVC解决跨域问题的原理也就是SpringMVC遵循了CORS通信的规则来解决了跨域的问题,在响应头中添加了一些CORS需要的信息。

    SpringMVC中提供了3种方案来解决跨域问题,下面一起来了解下。

    6、方案1:方法或者类上标注@CrossOrigin注解

    • 接口方法上标注org.springframework.web.bind.annotation.CrossOrigin注解,如下test1接口上标注了@CrossOrigin注解,这个接口就支持跨域访问,@CrossOrigin注解中含有更详细的配置,这里就不细说了

    • 也可以在类上标注@CrossOrigin注解,那么这个类中所有接口会支持跨域访问

    • 也可同时在类和方法上标注@CrossOrigin注解,最后方法上的跨域访问会取合并后的配置

      @RestController
      public?class?CorsController?{

      ???@RequestMapping(“/cors/test1”)
      ???@CrossOrigin
      ???public?List?test1()?{
      ???List?result?=?Arrays.asList(“www.itsoku.com”,
      ???“Spring高手系列”,
      ???“SpringMVC系列”,
      ???“MySQL系列”,
      ???“高并发系列”);
      ???return?result;
      ???}

      }

    7、方案2:全局配置的方式

    除了细粒度、基于注释的配置之外,您还可能需要定义一些全局CORS配置,这类似于使用筛选器,但可以声明为Spring MVC并结合细粒度@CrossOrigin配置。默认情况下,所有origins and GET, HEAD and POST methods是允许的。

    @EnableWebMvc
    @Configuration
    public?class?MvcConfig?implements?WebMvcConfigurer?{
    
    ????@Override
    ????public?void?addCorsMappings(CorsRegistry?registry)?{
    
    ????????//每次调用registry.addMappin可以添加一个跨域配置,需要多个配置可以多次调用registry.addMapping
    ????????registry.addMapping("/**")
    ????????????????.allowedOrigins("*")?//放行哪些原始域
    ????????????????.allowedMethods("PUT",?"DELETE","POST",?"GET")?//放行哪些请求方式
    ????????????????.allowedHeaders("header1",?"header2",?"header3")?//放行哪些原始请求头部信息
    ????????????????.exposedHeaders("header1",?"header2")?//暴露哪些头部信息
    ????????????????.allowCredentials(false)?//是否发送?Cookie
    ????????????????.maxAge(3600);
    
    ????????//?Add?more?mappings...
    ????}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    8、方案3:拦截器的方式CorsFilter

    //处理跨域的Filter
    //1.?添加?CORS配置信息
    CorsConfiguration?config?=?new?CorsConfiguration();
    //放行哪些原始域
    config.addAllowedOrigin("*");
    //是否发送?Cookie
    config.setAllowCredentials(false);
    //放行哪些请求方式
    config.addAllowedMethod("*");
    //放行哪些原始请求头部信息
    config.addAllowedHeader("*");
    //暴露哪些头部信息
    config.addExposedHeader("*");
    //2.?添加映射路径
    UrlBasedCorsConfigurationSource?corsConfigurationSource?=?new?UrlBasedCorsConfigurationSource();
    corsConfigurationSource.registerCorsConfiguration("/**",config);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    9、案例代码

    9.1、案例完整代码

    git地址:https://gitee.com/javacode2018/springmvc-series
    
    • 1

    3d7411716ff067929cb42621d933c9d7.png

    9.2、接口代码:CorsController

    CorsController中有2个接口,第一个接口上标注了@CrossOrigin注解,可以解决跨域访问的问题,而第二个方法没有标注。

    @RestController
    public?class?CorsController?{
    
    ????@RequestMapping("/cors/test1")
    ????@CrossOrigin
    ????public?List?test1()?{
    ????????List?result?=?Arrays.asList("www.itsoku.com",
    ????????????????"Spring高手系列",
    ????????????????"SpringMVC系列",
    ????????????????"MySQL系列",
    ????????????????"高并发系列");
    ????????return?result;
    ????}
    
    ????@RequestMapping("/cors/test2")
    ????public?List?test2()?{
    ????????List?result?=?Arrays.asList("www.itsoku.com",
    ????????????????"Spring高手系列",
    ????????????????"SpringMVC系列",
    ????????????????"MySQL系列",
    ????????????????"高并发系列");
    ????????return?result;
    ????}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    9.3、静态页面:cors.html

    静态页面cors.html中添加了2个按钮,点击2个按钮的时候,分别以ajax跨域的方式访问上面2个接口,第1个按钮访问第一个接口,第2个按钮访问第二个接口,然后在浏览器控制台查看效果。

    
    
    
    ????
    ????cors
    ????
    ????
    ????????$(function?()?{
    ????????????$("#cors-btn1").click(function?()?{
    ????????????????$.ajax({
    ????????????????????url:?"http://localhost:8080/chat21/cors/test1",
    ????????????????????success:?function?(data)?{
    ????????????????????????console.log(JSON.stringify(data));
    ????????????????????}
    ????????????????});
    ????????????});
    ????????????$("#cors-btn2").click(function?()?{
    ????????????????$.ajax({
    ????????????????????url:?"http://localhost:8080/chat21/cors/test2",
    ????????????????????success:?function?(data)?{
    ????????????????????????console.log(JSON.stringify(data));
    ????????????????????}
    ????????????????});
    ????????????});
    ????????})
    ????
    
    
    跨域测试test1
    跨域测试test2
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    9.4、将chat21-cores模块发布到tomcat

    792531c03b1c85711dc57f991427cbdf.png

    48184050be6c9c6cbc67255df00f8a26.png

    9.5、运行静态页面cors.html

    在idea中选中cors.html,然后鼠标右键->Run,即可运行

    8565b415d6802d16cdbb9cfb327bca2d.png

    运行效果如下(最好以chrome浏览器运行),idea中支持直接运行静态页面,大家注意这里的端口是63342,而上面tomcat的端口是8080,然后浏览器中按F12打开浏览器控制台,选中Console选项卡,稍后在这里可以看到点击按钮验证跨域的效果。

    bb7d440bed20cbf56442acf711530c2d.png

    9.6、点击第1个按钮,测试跨域正常请求

    824e402717cd7e34dac5cb65d39d7a88.png

    再看看下面这个图,正常的跨域请求,响应头多了几个头,主要是Access-Control开头的头是和CORS相关的,浏览器就是根据这些响应头来决定跨域访问是不是正常的,如果没有这些头,浏览器将拒绝读取响应体,然后就报错啦。

    609c1eec8c7da90c92a84d8564331f9a.png

    9.7、点击第2个按钮,测试跨域异常请求

    be1e2e9df68859f3dcd1ba6b54591650.png

    af8c0755a5e2baaae9f77c241b8a0b4a.png

    10、总结

    掌握SpringMVC中解决跨域问题的3种方式

    1. 注解的方式:@CrossOrigin

    2. 全局配置的方式:WebMvcConfigurer接口的addCorsMappings方法中注册CORS配置

    3. 拦截器的方式:CorsFilter

    11、SpringMVC系列目录

    1. SpringMVC系列第1篇:helloword

    2. SpringMVC系列第2篇:@Controller、@RequestMapping

    3. SpringMVC系列第3篇:异常高效的一款接口测试利器

    4. SpringMVC系列第4篇:controller常见的接收参数的方式

    5. SpringMVC系列第5篇:@RequestBody大解密,说点你不知道的

    6. SpringMVC系列第6篇:上传文件的 4 种方式,你都会么?

    7. SpringMVC系列第7篇:SpringMVC返回视图常见的 5 种方式,你会几种?

    8. SpringMVC系列第8篇:返回json & 通用返回值设计

    9. SpringMVC系列第9篇:SpringMVC返回null是什么意思?

    10. SpringMVC系列第10篇:异步处理

    11. SpringMVC系列第11篇:集成静态资源

    12. SpringMVC系列第12篇:拦截器

    13. SpringMVC系列第13篇:统一异常处理

    14. SpringMVC系列第14篇:实战篇:通用返回值 & 异常处理设计

    15. SpringMVC系列第15篇:全注解的方式?&?原理解析

    16. SpringMVC系列第16篇:通过源码解析SpringMVC处理请求的流程

    17. SpringMVC系列第17篇:源码解析SpringMVC容器的启动过程

    18. SpringMVC系列第18篇:强大的RequestBodyAdvice解密

    19. SpringMVC系列第19篇:强大的ResponseBodyAdvice解密

    20. SpringMVC系列第20篇:RestFull详解

    21. SpringMVC系列第21篇:接口调用过利器RestTemplate

    22. SpringMVC系列第22篇:参数解析器HandlerMethodArgumentResolver解密

    23. SpringMVC系列第23篇:@RequestParam用法及原理详解

    24. SpringMVC系列第24篇:@RequestBody用法及原理详解

    25. SpringMVC系列第25篇:@RequestHeader用法及原理详解

    26. SpringMVC系列第26篇:@CookieValue用法及原理详解

    27. SpringMVC系列第27篇:@RequestAttribute详解

    28. SpringMVC系列第28篇:@SessionAttribute详解

    29. SpringMVC系列第29篇:重定向和转向详解

    12、更多系列文章

    1. Spring高手系列(共56篇)

    2. Java高并发系列(共34篇)

    3. MySql高手系列(共27篇)

    4. Maven高手系列(共10篇)

    5. Mybatis系列(共12篇)

    6. 聊聊db和缓存一致性常见的实现方式

    7. 接口幂等性这么重要,它是什么?怎么实现?

    8. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

    13、最新资料

    1. 尚硅谷 Java 学科全套教程(总 207.77GB)

    2. 2021 最新版 Java 微服务学习线路图 + 视频

    3. 阿里技术大佬整理的《Spring 学习笔记.pdf》

    4. 阿里大佬的《MySQL 学习笔记高清.pdf》

    5. 2021 版 java 高并发常见面试题汇总.pdf

    6. Idea 快捷键大全.pdf

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    面试题:React实现一个Dialog模板
    openssl编程-基础知识-OpenSSL堆栈
    网站关键词-网站关键词设置方法-网站关键词排名优化软件
    C语言进阶篇——深度解剖数据在内存中的存储(配练习)
    [PyTorch][chapter 57][WGAN-GP 代码实现]
    NNDL:作业3
    grafana部署时集成自定义datasource和dashboard
    深度学习_18_模型的下载与读取
    CentOS7安装MongoDB
    基于人形检测的划区域客流统计
  • 原文地址:https://blog.csdn.net/segegefe/article/details/126114236