跨域与Spring Boot中CORS的应用

摘要:前后端独立开发期间,交互主要通过接口文档,前端Mock数据,后端使用Postman都不会发现跨域问题。当联调时前端尝试调用后端接口,这往往就需要需要处理的跨域问题……

        下面总结下跨域问题产生的前因后果以及如何通过CORS解决:

1. 什么是跨域?

        定义跨域之前,先介绍另外一个概念:同源策略。MDN给出的定义如下:

同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。 如果两个 URL 的协议、端口(如果有指定的话)和主机都相同的话,则这两个 URL 是同源的。

浏览器的同源策略 - Web 安全 | MDN同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。icon-default.png?t=N7T8https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

        浏览器的同源策略能阻隔恶意文档,减少可能被攻击的媒介。判断是否同源,是同源策略是否生效的关键。

        综上可知,跨域的是由于浏览器同源策略的安全限制,当一个域下的文档或脚本试图去请求另一个域下的资源时,如果域名、端口、协议任一不同,都会被浏览器视为跨域。

        需要注意:

        满足某些限制条件的情况下,页面是通过document.domain修改它的源,以通过同源检测

        需要注意的是跨域通常是浏览器的限制,实际请求已经正常发出且服务端已响应。

2. 跨域的解决方案有哪些?

        CORS (Cross-Origin Resource Sharing)

        CORS 是 HTTP 的一部分,它允许服务端来指定哪些可以从这个服务端加载资源。CORS方案的关键在于后端会在响应头中添加Access-Control-Allow-*头,浏览器将据此通过请求。

        CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

        同时满足以下条件则属于简单请求:

        请求方法属于:HEAD、GET、POST

         HTTP的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID、 Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/pla

跨域资源共享 CORS 详解 - 阮一峰的网络日志icon-default.png?t=N7T8https://www.ruanyifeng.com/blog/2016/04/cors.html

        对于简单请求,浏览器直接发出CORS请求,并在头信息之中增加Origin字段

GET /cors HTTP/1.1
Origin: http://imooc.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

        Origin非指定源,服务器返回http正常响应,没有包含Access-Control-Allow-Origin字段;则浏览器会报错并被XMLHttpRequest的onerror捕获(这种错误无法通过状态码识别,可能状态码为200)。如果Origin在指定域名中响应中会多出如下字段

Access-Control-Allow-Origin: http://imooc.com  // 请求的Origin或者*
Access-Control-Allow-Credentials: true  // 是否允许发送Cookie
Access-Control-Expose-Headers: FooBar  // 
Content-Type: text/html; charset=utf-8

        非简单请求的CORS请求,会在正式通信之前,增加一次OPTIONS查询请求,称为"预检"请求(preflight)。预检"请求"通过服务端返回的Access-Control-Allow-判断请求是否被允许。如果否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段,浏览器处理过程同简单请求非指定源。一旦预检"请求"包含Access-Control-Allow-,则通过预检,会跟简单请求一样再次发送请求。

        综上,CORS的本质是通过后端设置的响应头信息,告诉前端该请求是否支持跨域。

        CORS通常不需要前端改动,CORS请求默认不发送Cookie和HTTP认证信息;如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials: true;前端请求也需要配置xhr.withCredentials = true时,此外后端必须增加 response 头信息Access-Control-Allow-Origin(CORS),且必须指定具体域名,而不能指定为*。

axios.defaults.withCredentials = true;

        下文中的后端配置CORS会由于预检请求将会导致部分接口跨域不生效的问题。

        反向代理

        反向代理是在页面同域下配置一套反向代理服务,页面请求同域的服务端,服务端请求上游的实际的服务端,之后将结果返回给前端,完成将跨域请求转换为同源请求的操作。

        反向代理只需要后端处理即可,对前端同学来说太nice了!

        JSONP

        JSONP是利用<script>标签不存在跨域限制,历史悠久且只支持GET请求,且需要前后端配合支持。

3. Spring Boot中如何支持CORS

        Spring Boot中通过CORS解决跨域问题可以有多种实现方式:

        参考官网给出的示例:

CORS support in Spring FrameworkLevel up your Java code and explore what Spring can do for you.icon-default.png?t=N7T8https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

        3.1 使用注解@CrossOrigin,配置方法或者类的跨域
// **@CrossOrigin应用于单个方法**
@RestController
@RequestMapping("/account")
public class AccountController {

  @CrossOrigin   //
  @GetMapping("/{id}")
  public Account retrieve(@PathVariable Long id) {
    // ...
  }
}

//  **对Controller中所有方法使用@CrossOrigin
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)**
@RestController
@RequestMapping("/account")
public class AccountController {

  @GetMapping("/{id}")
  public Account retrieve(@PathVariable Long id) {
    // ...
  }

  @DeleteMapping("/{id}")
  public void remove(@PathVariable Long id) {
    // ...
  }
}

        注:当同时使用控制器级别和方法级别的CORS配置,Spring将合并两者的注解属性以创建一个合并后的CORS配置。

        3.2 添加全局配置解决跨域问题,则需要一个配置类:

        此处,通过全局配置CORS解决关于问题,增加配置类如下:

@Configuration
public class ImoocMallWebMvcConfig implements WebMvcConfigurer {
    @Override
    // 公共方法用于配置CORS跨域访问规则,接受一个CorsRegistry对象作为参数,用于配置CORS规则
    public void addCorsMappings(CorsRegistry registry) {
        // registry对象调用addMapping方法,指定允许跨域请求的路径为所有路径("/**")
        registry.addMapping("/**")
                .allowedOrigins("*")  // 设置允许跨域请求的来源,此处为允许所有来源
                .allowedMethods("GET", "POST", "PUT","OPTIONS", "DELETE")  // 设置允许的HTTP请求方法
                .maxAge(3600)  // 设置预检请求的有效期,单位为秒
                .allowCredentials(true);  // 设置是否允许请求携带认证信息(如cookies、HTTP认证及客户端SSL证明),此处允许请求携带认证信息
    }
}

 常见的 CORS 配置项:

  • allowedOrigins(String... origins):允许访问的来源,可以是一个字符串数组。
  • allowedMethods(String... methods):允许的 HTTP 方法,如 GET、POST 等。
  • allowedHeaders(String... headers):允许的请求头。
  • exposedHeaders(String... headers):允许暴露给客户端的响应头名称。
  • allowCredentials(boolean allowCredentials):是否允许发送身份验证信息(如 cookies)
  •  maxAge(long maxAge):预检请求的缓存时间,以秒为单位。
  • allowedPublicApis(String... publicApis):允许的公共 API。

         启用上述全局配置后出现另外一问题:部分接口有效(可发送跨域请求),部分接口依然提示跨域问题。尝试通过对单个接口或者类中配置@CrossOrigin依然无效。发现此时单独访问接口(双击网络面板的接口)会提示"NEED_JWT_TOKEN",应该是拦截位置导致的,部分接口拦截了部分过滤器未拦截,最终定位产生这个问题的原因是由于:

        "预检"请求(preflight)

        请求方法:OPTIONS

        根据Header信息判断是否为预检请求,这个请求可以避免直接请求操作了服务端数据,却没被前端获取响应,是对后端数据一种保护。此处,为避免预检请求被拦截,对OPTIONS请求直接放行。

HttpServletRequest request = (HttpServletRequest) servletRequest;
if ("OPTIONS".equals(request.getMethod())) {
    // 放行预检请求,按照原有逻辑执行
    filterChain.doFilter(servletRequest, servletResponse);
}
        3.3 使用mvc XML命名空间来配置CORS

        官网给出的示例,可按照如下格式声明多个CORS映射

<mvc:cors>
  <mvc:mapping path="/api/**"
    allowed-origins="http://domain1.com, http://domain2.com"
    allowed-methods="GET, PUT"
    allowed-headers="header1, header2, header3"
    exposed-headers="header1, header2" allow-credentials="false"
    max-age="123" />
  <mvc:mapping path="/resources/**"
    allowed-origins="http://domain1.com" />
</mvc:cors>
        3.4 基于过滤器的CORS支持

        除了上述方式Spring Framework还提供了CorsFilter,在过滤器中声明格式如下:

@Configuration
public class MyConfiguration {

  @Bean
  public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    **config.setAllowCredentials(true);
    config.addAllowedOrigin("http://domain1.com");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");**
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/486317.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

day03_mysql_课后练习 - 参考答案

文章目录 day03_mysql_课后练习mysql练习题第1题第2题第3题第4题第5题 day03_mysql_课后练习 mysql练习题 第1题 案例&#xff1a; 1、创建一个数据库&#xff1a;day03_test01_school 2、创建如下表格 表1 Department表的定义 字段名字段描述数据类型主键外键非空唯一D…

Java学习笔记 | JavaSE基础语法 | 04 | 数组

文章目录 0.前言1.数组2.数组声明2.1 数组定义2.2 数组初始化1.静态初始化2.动态初始化3.区别4.数组的默认初始化值&#xff1a; 2.3 数组名 3.访问数组3.1 索引3.2 访问数组3.3 length属性 4.数组常见问题5.数组内存分析5.1 内存分配5.2 数组内存分配 6.数组的练习练习1&#…

用Springboot(java程序)访问Salesforce RestAPI

本文讲一下&#xff0c;如何从0构建一个Springboot的应用程序&#xff0c;并且和Salesforce系统集成&#xff0c;取得Salesforce里面的数据。 一、先在Salesforce上构建一个ConnectApp。 有了这个&#xff0c;SF才允许你和它集成。手顺如下&#xff1a; 保存后&#xff0c;…

华为ensp中vrrp虚拟路由器冗余协议 原理及配置命令

CSDN 成就一亿技术人&#xff01; 作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; CSDN 成就一亿技术人&#xff01; ————前言————— VRRP&#xff08;Virtual Router Redundancy Protocol&#xff0c;虚拟路由器冗余协议&#xff0…

使用 CSS 预处理器的优缺点

使用CSS预处理器在前端开发中已经成为一种流行的趋势&#xff0c;它们提供了一种更灵活、更高效的方式来编写和管理样式表。然而&#xff0c;就像任何工具一样&#xff0c;CSS预处理器也有其优点和缺点。本文将深入探讨使用CSS预处理器的优缺点&#xff0c;并讨论如何在项目中明…

Luminar Neo:让每一张照片都散发独特魅力 mac/win版

Luminar Neo是一款引领摄影艺术新纪元的智能影像处理软件。它融合了先进的算法和人工智能技术&#xff0c;为摄影师提供了前所未有的创作自由度和影像处理能力。 Luminar Neo软件获取 作为一款强大的后期处理工具&#xff0c;Luminar Neo不仅具备丰富的调整选项和滤镜效果&…

MES管理系统生产调度模块的工作原理是什么

在现代制造业中&#xff0c;MES管理系统发挥着举足轻重的作用&#xff0c;其中的生产调度模块更是整个生产流程的核心。它集成了自动排产和手动排产的功能&#xff0c;能够精确安排每个工单在各个工序的具体生产线体、计划开始时间和计划结束时间&#xff0c;从而确保生产的高效…

一分钟学习Markdown语法

title: 一分钟学习Markdown语法 date: 2024/3/24 19:33:29 updated: 2024/3/24 19:33:29 tags: MD语法文本样式列表结构链接插入图片展示练习实践链接问题 欢迎来到Markdown语法的世界&#xff01;Markdown是一种简单而直观的标记语言&#xff0c;让文本排版变得轻松有趣。接下…

javaSwing超级玛丽游戏

一、摘要 摘要 近年来&#xff0c;Java作为一种新的编程语言&#xff0c;以其简单性、可移植性和平台无关性等优点&#xff0c;得到了广泛地应用。J2SE称为Java标准版或Java标准平台。J2SE提供了标准的SDK开发平台。利用该平台可以开发Java桌面应用程序和低端的服务器应用程序…

Redis分布式锁—SETNX+Lua脚本实现

使用redis实现分布式锁&#xff0c;就是利用redis中的setnx&#xff0c;如果key不存在则进行set操作返回1&#xff0c;key已经存在则直接返回0。 优点&#xff1a; 设置expiretime过期时间&#xff0c;可以避免程序宕机长期持有锁不释放。redis作为一个中间服务&#xff0c;所…

下载的音频转换成mp3怎么转?4个好用简单的方法

不同音乐平台下载的音频格式文件不同&#xff0c;比如网易云的ncm格式、酷狗的kgm格式、B站的m4s格式、微信语音的silk格式、手机录音的amr、m4a格式&#xff0c;这些音频一旦脱离了原本的平台便无法播放&#xff0c;那么如何把下载的音频转换成兼容性高的MP3格式以便于我们在更…

linux系统------------Mysql数据库介绍、编译安装

目录 一、数据库基本概念 1.1数据(Data) 1.2表 1.3数据库 1.4数据库管理系统(DBMS) 数据库管理系统DBMS原理 1.5数据库系统&#xff08;DBS) 二、数据库发展史 1、第一代数据库 2、第二代数据库 3、第三代数据库 三、关系型数据库 3.1关系型数据库应用 3.2主流的…

Java生成p12证书

本文章使用的环境 jdk1.8&#xff0c;spring-boot2.6.13 一、pom依赖 <dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.49</version></dependency><dependency>&…

说一说Java中的四种引用类型?

引言 在JDK1.2之前Java并没有提供软引用、弱引用和虚引用这些高级的引用类型。而是提供了一种基本的引用类型&#xff0c;称为Reference。并且当时Java中的对象只有两种状态&#xff1a;被引用和未被引用。当一个对象被引用时&#xff0c;它将一直存在于内存中&#xff0c;直到…

NSCaching: Simple and Efficient NegativeSampling for Knowledge Graph Embedding

摘要 知识图嵌入是数据挖掘研究中的一个基本问题&#xff0c;在现实世界中有着广泛的应用。它的目的是将图中的实体和关系编码到低维向量空间中&#xff0c;以便后续算法使用。负抽样&#xff0c;即从训练数据中未观察到的负三元组中抽取负三元组&#xff0c;是KG嵌入的重要步…

优思学院|质量工程师的该有哪些技能与素养?

质量工程师作为制造业中的核心角色&#xff0c;致力于确保产品的整体质量。这不仅涉及到测试和监控过程&#xff0c;还包括创建文档、设计质量测试&#xff0c;并且定义测试结果应达到的标准&#xff0c;所以他既懂得生产技术&#xff0c;又精通管理知识。在本篇文章中&#xf…

springboot3使用​自定义注解+Jackson优雅实现接口数据脱敏

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途 目录 写在前面 内容简介 实现思路 实现步骤 1.自定义脱敏注解 2.编写脱敏策略枚举类 3.编写JSON序列化实现 4.编写测…

【Python小工具系列】使用 Python 循环批量打开网页链接

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

工程项目管理系统专业解决方案!企智汇工程项目管理专业解决方案!

1.企智汇工程项目管理系统打造数智化全流程平台&#xff0c;打通全公司数据&#xff0c;实现公司业财一体化全方位管理。 企智汇工程项目管理系统&#xff0c;打通钉钉与企业微信的入口、可与财务系统做数据对接&#xff0c;统一共享数据源的企业一站式数智化项目管理平台&…

openGauss学习笔记-250 openGauss性能调优-使用Plan Hint进行调优-Join方式的Hint

文章目录 openGauss学习笔记-250 openGauss性能调优-使用Plan Hint进行调优-Join方式的Hint250.1 功能描述250.2 语法格式250.3 参数说明250.4 示例 openGauss学习笔记-250 openGauss性能调优-使用Plan Hint进行调优-Join方式的Hint 250.1 功能描述 指明Join使用的方法&#…