今天和小伙伴们来聊一聊通过CORS解决跨域问题。

同源策略

很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。

同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是 JSONP,JSONP 虽然能解决跨域但是有一个很大的局限性,那就是只支持 GET 请求,不支持其他类型的请求,而今天我们说的 CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个 W3C 标准,它是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是 JSONP 模式的现代版。

在 Spring 框架中,对于 CORS 也提供了相应的解决方案,今天我们就来看看 SpringBoot 中如何实现 CORS。

实践

接下来我们就来看看 Spring Boot 中如何实现这个东西。

首先创建两个普通的 Spring Boot 项目,这个就不用我多说,第一个命名为 provider 提供服务,第二个命名为 consumer 消费服务,第一个配置端口为 8080,第二个配置配置为 8081,然后在 provider 上提供两个 hello 接口,一个 get,一个 post,如下:

@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@PostMapping("/hello")
public String hello2() {
return "post hello";
}
}

在 consumer 的 resources/static 目录下创建一个 html 文件,发送一个简单的 ajax 请求,如下:

<div id="app"></div>
<input type="button" onclick="btnClick()" value="get_button">
<input type="button" onclick="btnClick2()" value="post_button">
<script>
function btnClick() {
$.get('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
});
} function btnClick2() {
$.post('http://localhost:8080/hello', function (msg) {
$("#app").html(msg);
});
}
</script>

然后分别启动两个项目,发送请求按钮,观察浏览器控制台如下:

Access to XMLHttpRequest at 'http://localhost:8080/hello' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

可以看到,由于同源策略的限制,请求无法发送成功。

使用 CORS 可以在前端代码不做任何修改的情况下,实现跨域,那么接下来看看在 provider 中如何配置。首先可以通过 @CrossOrigin 注解配置某一个方法接受某一个域的请求,如下:

@RestController
public class HelloController {
@CrossOrigin(value = "http://localhost:8081")
@GetMapping("/hello")
public String hello() {
return "hello";
} @CrossOrigin(value = "http://localhost:8081")
@PostMapping("/hello")
public String hello2() {
return "post hello";
}
}

这个注解表示这两个接口接受来自 http://localhost:8081 地址的请求,配置完成后,重启 provider ,再次发送请求,浏览器控制台就不会报错了,consumer 也能拿到数据了。

此时观察浏览器请求网络控制台,可以看到响应头中多了如下信息:

这个表示服务端愿意接收来自 http://localhost:8081 的请求,拿到这个信息后,浏览器就不会再去限制本次请求的跨域了。

provider 上,每一个方法上都去加注解未免太麻烦了,有的小伙伴想到可以讲注解直接加在 Controller 上,不过每个 Controller 都要加还是麻烦,在 Spring Boot 中,还可以通过全局配置一次性解决这个问题,全局配置只需要在 SpringMVC 的配置类中重写 addCorsMappings 方法即可,如下:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8081")
.allowedMethods("*")
.allowedHeaders("*");
}
}

/** 表示本应用的所有方法都会去处理跨域请求,allowedMethods 表示允许通过的请求数,allowedHeaders 则表示允许的请求头。经过这样的配置之后,就不必在每个方法上单独配置跨域了。

存在的问题

了解了整个 CORS 的工作过程之后,我们通过 Ajax 发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法,举个例子:

假如一家银行用以运行转账操作的URL地址如下:http://icbc.com/aa?bb=cc,那么,一个恶意攻击者可以在另一个网站上放置如下代码:<img src="http://icbc.com/aa?bb=cc">,如果用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会遭受损失。

基于此,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,预先请求会首先发送一个 options 探测请求,和浏览器进行协商是否接受请求。默认情况下跨域请求是不需要凭证的,但是服务端可以配置要求客户端提供凭证,这样就可以有效避免 csrf 攻击。

好了,这个问题就说这么多,关于 Spring Boot 中的 CORS ,松哥还有一个小小的视频教程

关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

Spring Boot2 系列教程(十四)CORS 解决跨域问题的更多相关文章

  1. Spring Boot2 系列教程 (十四) | 统一异常处理

    如题,今天介绍 SpringBoot 是如何统一处理全局异常的.SpringBoot 中的全局异常处理主要起作用的两个注解是 @ControllerAdvice 和 @ExceptionHandler ...

  2. Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker

    今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...

  3. Spring Boot2 系列教程(十二)@ControllerAdvice 的三种使用场景

    严格来说,本文并不算是 Spring Boot 中的知识点,但是很多学过 SpringMVC 的小伙伴,对于 @ControllerAdvice 却并不熟悉,Spring Boot 和 SpringM ...

  4. Spring Boot2 系列教程(十六)定时任务的两种实现方式

    在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Qua ...

  5. Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置

    用过 Spring Boot 的小伙伴都知道,我们只需要在项目中引入 spring-boot-starter-web 依赖,SpringMVC 的一整套东西就会自动给我们配置好,但是,真实的项目环境比 ...

  6. Spring Boot2 系列教程 (十八) | 整合 MongoDB

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 如题,今天介绍下 SpringBoot 是如何整合 MongoDB 的. MongoDB 简介 MongoDB 是由 C++ ...

  7. Spring Boot2 系列教程 (十二) | 整合 thymeleaf

    前言 如题,今天介绍 Thymeleaf ,并整合 Thymeleaf 开发一个简陋版的学生信息管理系统. SpringBoot 提供了大量模板引擎,包含 Freemarker.Groovy.Thym ...

  8. Spring Boot2 系列教程 (十) | 实现声明式事务

    前言 如题,今天介绍 SpringBoot 的 声明式事务. Spring 的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了 API 用于开启事务.提交事务来完成数据操作,或者在发生错误 ...

  9. Spring Boot2 系列教程(十五)定义系统启动任务的两种方式

    在 Servlet/Jsp 项目中,如果涉及到系统任务,例如在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行,这里,容易想到web基础中的三大组件( ...

随机推荐

  1. springmvc项目中的中文乱码的解决及未生效解决

    情景: springmvc项目中,在控制台输出时中文乱码,在web网页中正常. 解决方法: 在web.xml中添加如下代码: <!-- 中文乱码解决 --> <filter> ...

  2. ios 把数组对象转成json字符串存起来

    1第一步是我们获取数据源 一般我们都是从接口请求数据 NSArray *subColumnsArray = nil; NSDictionary *dict = [NSJSONSerialization ...

  3. HTML5实现首页动态视频背景

    话不多说,先看效果图: ​​​ 炫酷吗?你想实现这种动态视频作为背景的首页吗?来,一起来学习,本文将带你一起实现H5动态视频背景: 首先网上找一段清晰的视频下载下来,最好是MP4格式的: 下载好了之后 ...

  4. DOM之事件(一)

    DOM事件,就是浏览器或用户针对页面可以做出的某种动作,我们称这些动作为DOM事件.它是用户和页面交互的核心.当动作发生(事件触发)时,我们可以为其绑定一个或多个事件处理程序(函数),来完成我们想要实 ...

  5. StackOverflow 第四周周报及19年就业情况分析

    这是 Stack Overflow 第四周周报,两篇 Java.两篇 Python.公众号「渡码」为日更,欢迎关注.另外,我搜集了今年的就业数据,对招聘情况和岗位情况做了简单总结,想了解的朋友点这里. ...

  6. 第六届蓝桥杯java b组第三题

    第三题 三羊献瑞 观察下面的加法算式: 其中,相同的汉字代表相同的数字,不同的汉字代表不同的数字. 请你填写“三羊献瑞”所代表的4位数字(答案唯一),不要填写任何多余内容. 答案这个题目完全可以使用暴 ...

  7. Scrapy项目 - 数据简析 - 实现斗鱼直播网站信息爬取的爬虫设计

    一.数据分析截图(weka数据分析截图 2-3个图,作业文字描述) 本次将所爬取的数据信息,如:房间数,直播类别和人气,导入Weka 3.7工具进行数据分析.有关本次的数据分析详情详见下图所示:   ...

  8. Python学习笔记整理总结【Django】:中间件、CSRF、缓存

     一.中间件  中间件是一类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法:在django项目的settings模块中,有一个 MIDDLEWARE 变量,其中每 ...

  9. MySQL数据库忘记密码怎么办?

    忘记MySQL数据库密码就进不去数据库,也就无法修改密码,解决方法如下: 1:打开cmd命令符,先关闭正在运行的数据库,输入如下命令: 2:打开mysql.exe和mysqld.exe所在的文件夹,复 ...

  10. CSS技巧 (3)

    关于CSS技巧的一些题目 题目列表 所有答案点击题目链接 1.下面这个左边竖条图形,只使用一个标签,可以有多少种实现方式: 2.类似下面这样的条纹边框,只使用一个标签,可以有多少种实现方式 -- 从条 ...