springboot 配置跨域访问

什么是 CORS?

CORS,全称是“跨源资源共享”(Cross-Origin Resource Sharing),是一种Web应用程序的安全机制,用于控制不同源的资源之间的交互。

在Web应用程序中,CORS定义了一种机制,通过该机制,浏览器能够限制哪些外部网页可以访问来自不同源的资源。源由协议、域名和端口组成。当一个网页请求另一个网页上的资源时,浏览器会检查请求是否符合CORS规范,以确定是否允许该请求。

CORS的工作原理是:当浏览器发送一个跨域请求时,它会附加一些额外的头部信息到请求中,这些头部信息包含了关于请求的来源和目的的信息。服务器可以检查这些头部信息并决定是否允许该请求。如果服务器允许请求,它会返回一个响应,其中包含一个名为“Access-Control-Allow-Origin”的头部信息,该信息指定了哪些源可以访问该资源。浏览器会检查返回的“Access-Control-Allow-Origin”头部信息,以确定是否允许该跨域请求。

通过使用CORS,开发人员可以控制哪些外部网页可以访问他们的资源,从而提高应用程序的安全性。

Spring Boot 如何配置 CORS?

Spring Boot对于跨域请求的支持可以通过两种配置方式来实现:

  1. 注解配置:可以使用@CrossOrigin注解来启用CORS。例如,在需要支持跨域请求的方法上添加@CrossOrigin注解,并配置好origins和maxAge等参数。
  2. 全局配置:可以通过实现WebMvcConfigurer接口并注册一个WebMvcConfigurer bean来配置CORS的全局设置。在实现类中覆盖addCorsMappings方法,通过CorsRegistry对象添加映射规则。默认情况下,所有方法都支持跨域,并且GET、POST和HEAD请求是被允许的。如果需要自定义,可以配置CorsRegistry对象来指定允许的域名、端口和请求方法等。
  3. 过滤器配置:可以通过CorsFilter bean来配置CORS的过滤器。这种方式可以更加灵活地控制CORS的配置,例如只允许特定的域名进行跨域访问等。

前端代码 

request.ts

import axios from "axios";const myAxios = axios.create({baseURL: process.env.VUE_APP_API_BASE_URL,timeout: 10000,// 携带cookiewithCredentials: true,
});// 添加请求拦截器
myAxios.interceptors.request.use(function (config) {// 在发送请求之前做些什么return config;},function (error) {// 对请求错误做些什么return Promise.reject(error);}
);// 添加响应拦截器
myAxios.interceptors.response.use(function (response) {// 2xx 范围内的状态码都会触发该函数。// 对响应数据做点什么return response;},function (error) {// 超出 2xx 范围的状态码都会触发该函数。// 对响应错误做点什么return Promise.reject(error);}
);export default myAxios;

user.ts

import myAxios from "@/utils/request";/*** 获取用户列表* @param username*/
export const searchUsers = async () => {return myAxios.request({url: `/admin/findAll`,method: "GET",});
};};

 vue页面使用

<script setup lang="ts">
import { searchUsers } from "@/api/user";searchUsers().then((res) => {console.log(res);
});
</script>

一、 在 Controller 上添加 @CrossOrigin 注解

这种方式适合只有一两个rest接口需要跨域或者没有网关的情况下

@RestController
@CrossOrigin(origins = {"http://127.0.0.1:9527"}, allowCredentials = "true")
public class HelloController {@GetMapping("/hello")public String hello(){return "Hello";}}

@CrossOrigin 注解有几个属性,允许你更精细地控制跨域行为:

* origins: 允许的源列表,可以是域名、IP 或其他标识符。多个源可以使用逗号分隔。

* methods: 允许的 HTTP 方法列表。例如,只允许 GET 请求。

* allowedHeaders: 允许的请求头列表。默认情况下,允许所有请求头。

* allowCredentials:是否允许携带cookie;值为true、false的字符串

* maxAge: 预检请求的缓存时间(以秒为单位)。默认是 86400 秒(24小时)

二、增加 WebMvcConfigurer 全局配置 

如果有大量的rest接口的时候,显然第一种方案已经不适合了,工作量大,也容易出错,那就通过全局配置的方式,允许SpringBoot端所有的rest接口都支持跨域访问

addCorsMappings 是 Spring Boot 中用于配置跨域请求的方法。它允许你指定哪些路径的请求需要进行跨域处理,以及如何处理这些请求。

@Configuration
public class CrosConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {// 允许所有请求路径跨域访问registry.addMapping("/**") // 是否携带Cookie,默认false.allowCredentials(true) // 允许的请求头类型.allowedHeaders("*")// 预检请求的缓存时间(单位:秒).maxAge(3600)  // 允许的请求方法类型.allowedMethods("*") // 允许哪些域名进行跨域访问.allowedOrigins("http://127.0.0.1:5500");}
}

假如我们配置了 addCorsMappings ,项目里还用了 Interceptor,此时就会发生问题!

例如部分接口需要 jwt 权限验证:

 public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/user/**").excludePathPatterns("/login");}

正常请求是没问题的,但是部分请求没带 token 的话,此时浏览器直接报跨域问题,好像 addCorsMappings 失效了一样。

主要原因是因为请求顺序导致的,请求会先进入拦截器,默认配置了 addCorsMappings 操作后,实际上会加了一个 CorsInterceptor,但是这个拦截器的优先级在最后。

所以,如果一个请求被前面的拦截器拦截后,直接返回,就不会经过 CorsInterceptor,这样一来返回的响应头上就不包含跨域的相关信息,因此浏览器就会继续报跨域错误!

此时有一种方法,就是在 JwtInterceptor 内直接放行预检请求,让它能访问到 CorsInterceptor 添加响应头。

if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {return true;
}

 还有一种更优雅的方式就是使用 CorsFilter

Filter 是过滤器,它是属于 servlet,而 Interceptor 是属于 Spring 的,因此 Filter 执行的优先级高于 Interceptor。

三、过滤器配置 

在Spring Boot中,CorsFilter用于处理跨域请求。它是一个过滤器,用于在Spring应用程序中启用CORS(跨源资源共享)支持。


/*** 简单跨域就是GET,HEAD和POST请求,但是POST请求  的"Content-Type"只能是* application/x-www-form-urlencoded, multipart/form-data 或 text/plain* 反之,就是非简单跨域,此跨域有一个预检机制,会发两次请求,一次OPTIONS请求,一次真正的请求,* OPTIONS请求服务器确认允许的请求方法,请求域等信息,符合要求发真正的请求,不符合报 cors 错误
*/
@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter(){CorsConfiguration config = new CorsConfiguration();config.addAllowedHeader("*");config.addAllowedMethod("*");config.addAllowedOriginPattern("http://127.0.0.1:5500");config.setAllowCredentials(true);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**",config);return  new CorsFilter(source);}

注意事项 

当我们没有配置跨域的时候会提示:

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

当我们前端开启 withCredentials:true 的时候,后端没有配置allowCredentials为true会提示: 

Access to XMLHttpRequest at 'http://localhost:8080/hello' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

当我们在后端配置了allowCredentials(true)那么就不能配置allowedOrigins("*"),必须指定来源 或者使用  allowedOriginPatterns(*)

jakarta.servlet.ServletException: Request processing failed: java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.

以上这种方案如果微服务多的话,需要在每个服务的主类上都加上这么段代码,增加了维护量。

以上三种方案都是在SpringBoot的基础上实现的解决方案,在模块较多或者接口较多的情况下不易维护。

既然SpringCloud自带Gateway,下面就讲讲使用Gateway的跨域解决方案。

Spring cloud Gateway 配置CORS

过滤器配置

这种方案跟方案三有些类似,只不过是放到了Gateway端,对于有多个微服务模块的情况下,就大大减少了SpringBoot模块端的代码量,让各个模块更集中精力做业务逻辑实现。这个方案只需要在Gateway里添加Filter代码类即可。

public class CorsWebFilter implements WebFilter {private static final String ALL = "*";private static final String MAX_AGE = "18000L";@Overridepublic Mono<Void> filter(ServerWebExchange ctx, WebFilterChain chain) {ServerHttpRequest request = ctx.getRequest();String path = request.getPath().value();ServerHttpResponse response = ctx.getResponse();if ("/favicon.ico".equals(path)) {response.setStatusCode(HttpStatus.OK);return Mono.empty();}if (!CorsUtils.isCorsRequest(request)) {return chain.filter(ctx);}HttpHeaders requestHeaders = request.getHeaders();HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();HttpHeaders headers = response.getHeaders();headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());if (requestMethod != null) {headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());}headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);if (request.getMethod() == HttpMethod.OPTIONS) {response.setStatusCode(HttpStatus.OK);return Mono.empty();}return chain.filter(ctx);}
}

 或者这样

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;@Configuration
public class BeanConfig {/*** 跨域配置** @return*/@Beanpublic WebFilter corsFilter() {return (ServerWebExchange ctx, WebFilterChain chain) -> {ServerHttpRequest request = ctx.getRequest();if (!CorsUtils.isCorsRequest(request)) {return chain.filter(ctx);}HttpHeaders requestHeaders = request.getHeaders();ServerHttpResponse response = ctx.getResponse();HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();HttpHeaders headers = response.getHeaders();String origin = requestHeaders.getOrigin();// 设置允许跨域headers.setAccessControlAllowCredentials(true);headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);if (requestMethod != null) {headers.set(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());}headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");headers.set(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "180");if (request.getMethod() == HttpMethod.OPTIONS) {response.setStatusCode(HttpStatus.OK);return Mono.empty();}return chain.filter(ctx);};}}

Gateway配置文件

修改配置文件即可,结合配置中心使用,可以实现动态修改。

application.yml 

spring:cloud:gateway:      globalcors:        corsConfigurations:'[/**]': allowedOrigins: "http://domain.com"allowedMethods:- GET- POST

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

应用于蛋白-小分子柔性对接的等变VAE模型 - FlexPose 测评

FlexPose 应用于蛋白-小分子柔性对接场景下&#xff0c;能够在欧几里得空间中直接对蛋白-小分子复合结构的进行预测的等变神经网络模型&#xff0c;而无需传统的采样和评分策略。此模型考虑了蛋白氨基酸主链和侧链的柔性&#xff0c;会根据小分子的情况对氨基酸的侧链和主链进行…

【Web前端】如何构建简单HTML表单?

HTML 表单是 Web 开发中非常重要的组成部分。它们是与用户交互的主要方式&#xff0c;能够收集用户输入的数据。表单的灵活性使它们成为 HTML 中最复杂的结构之一&#xff0c;但若使用正确的结构和元素&#xff0c;可以确保其可用性和无障碍性。 表单的基本结构 HTML 表单使用…

Spring Boot英语知识分享网站:技术与实践

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

乌班图单机(不访问外网)部署docker和服务的方法

面向对象:Ubuntu不能访问外网的机子,部署mysql、redis、jdk8、minio 过程: 1、安装docker(照着图去这里找对应的下载下来https://download.docker.com/linux/static/stable/),将7个docker官网下载的文件下载下来后,传上去服务器随便一个文件夹或者常用的opt或者/usr/lo…

IDEA全局设置-解决maven加载过慢的问题

一、IDEA全局设置 注意&#xff1a;如果不是全局设置&#xff0c;仅仅针对某个项目有效&#xff1b;例在利用网上教程解决maven加载过慢的问题时&#xff0c;按步骤设置却得不到解决&#xff0c;原因就是没有在全局设置。 1.如何进行全局设置 a.在项目页面&#xff0c;点击f…

狂野飙车8+(Asphalt 8+) for Mac 赛车竞速游戏 安装教程

Mac分享吧 文章目录 狂野飙车8(Asphalt 8) for Mac 赛车竞速游戏软件 效果图展示一、狂野飙车8(Asphalt 8) 赛车竞速游戏 Mac电脑版——v2.1.11️⃣&#xff1a;下载软件2️⃣&#xff1a;安装软件2.1 左侧安装包拖入右侧文件夹中&#xff0c;等待安装完成&#xff0c;运行软件…

标贝科技:自动驾驶中的数据标注类别分享

国内的自动驾驶行业正处于快速发展阶段。伴随随着芯片算力的提升、算法的优化以及数据采集标注传感设备的日益成熟&#xff0c;自动驾驶技术正逐步从实验室转向商业化应用。电车时代的来临&#xff0c;加速了自动驾驶时代的全面降临&#xff0c;23年国内汽车行业内卷的开始&…

(详细文档!)java swing学生信息管理系统 +mysql

第一章&#xff1a;系统功能分析 1.1、系统简介与开发背景 学生信息管理系统是在信息化时代&#xff0c;特别是在教育领域中产生的。随着学校规模的不断扩大和信息化技术的不断发展&#xff0c;传统的纸质档案管理方式已经无法满足学校对学生信息管理的需求&#xff0c;因此需…

JVM逃逸分析机制

JVM逃逸分析机制 简单来说&#xff0c;逃逸分析是分析了对象是否只在当前函数范围内使用&#xff0c;来确定是否在栈上进行分配&#xff0c;主要涉及到栈是函数运行完&#xff0c;立即清理的&#xff0c;所以不需要等到gc了&#xff0c;为了大大缓解了gc的压力。 一、定义 JVM…

【Petri网导论学习笔记】Petri网导论入门学习(十) —— 3.2 关联矩阵与状态方程

目录 3.2 关联矩阵与状态方程定义 3.3 关联矩阵引理 3.4引理 3.5定理 3.4例 3.7例 3.83.2 关联矩阵与状态方程 正如 Petri 网的一个标识可以表示成一个 $ m $ 维非负整数向量一样,Petri 网的结构也可以用一个矩阵来表示。这样,就可以引入线性代数的方法对 Petri 网的性质进行…

微信小程序常用全局配置项及窗口组成部分详解

微信小程序常用全局配置项及窗口组成部分详解 引言 微信小程序作为一种新兴的应用形态,凭借其轻量级、便捷性和丰富的功能,已成为开发者和用户的热门选择。在开发小程序的过程中,了解全局配置项和窗口组成部分是至关重要的。本文将详细介绍微信小程序的常用全局配置项及窗…

【H2O2|全栈】Node.js(1)

目录 前言 开篇语 准备工作 ES6导入导出 导入 有名导出 匿名导出 Node概念 Node导入导出 导入 有名导出 匿名导出 Node常用模块 path模块 和路径有关的全局变量 常见方法 导入方法 fs模块 常见方法 导入方法 结束语 前言 开篇语 本系列博客主要分享Java…

matlab -炉温串级控制PID

1、内容简介 略 92-可以交流、咨询、答疑 2、内容说明 略 基于PID的反馈控制能够使得炉温控制达到较好的控制效果&#xff0c;但系统的调节时间还是较长&#xff0c;一般都大于20分钟。考虑能否用其他系统来改进控制系统使得调节时间变短的同时还能满足控制要求。一种最直接…

#渗透测试#红蓝攻防#HW#经验分享#溯源反制

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章阅 目录 一、溯源反制 1、溯源反制的重要性 2、溯源…

java——SpringBoot中常用注解及其底层原理

SpringBoot中的注解是简化配置、自动装配组件和实现声明式服务的关键。以下是对SpringBoot中常用注解及其底层原理的详细解析&#xff1a; 常用注解 SpringBootApplication 标注在主程序类上&#xff0c;表示这是一个Spring Boot应用的入口。它是一个复合注解&#xff0c;包括…

redis-cluster集群搭建

集群节点信息 192.168.222.131:46379 主要节点1 192.168.222.131:46380 从节点1 192.168.222.131:46381 从节点2192.168.222.132:46379 主要节点2 192.168.222.132:46380 从节点1 192.168.222.132:46381 从节点2192.168.222.133:46379 主要节点3 192.168.222.133:46380 从节点…

探索Python WebSocket新境界:picows库揭秘

文章目录 探索Python WebSocket新境界&#xff1a;picows库揭秘第一部分&#xff1a;背景介绍第二部分&#xff1a;picows库概述第三部分&#xff1a;安装picows库第四部分&#xff1a;简单库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方案第…

QT-installEventFilter

installEventFilter 是 Qt 框架中的一个方法&#xff0c;用于在对象之间建立事件过滤机制。具体来说&#xff0c;它允许一个对象&#xff08;称为事件过滤器&#xff09;监视另一个对象&#xff08;称为被监视对象&#xff09;的事件&#xff0c;并在这些事件被处理之前对其进行…

dmdba用户资源限制ulimit -a 部分配置未生效

dmdba用户资源限制ulimit -a 部分配置未生效 1 环境介绍2 数据库实例日志报错2.1 mpp01 实例日志报错2.2 mpp02 实例日志报错 3 mpp02 服务器资源限制情况4 关闭SELinux 问题解决4.1 临时关闭 SELinux4.2 永久关闭 SELinux 5 达梦数据库学习使用列表 1 环境介绍 Cpu x86 Os Ce…

Linux基本指令的使用

当然可以&#xff01;以下是一些常用的Linux指令及其示例&#xff1a; 1. ls 列出目录内容。 ls 显示当前目录下的文件和文件夹。 ls -l 以详细格式列出文件和文件夹的信息&#xff08;如权限、拥有者、大小等&#xff09;。 2. cd 改变当前目录。 cd /path/to/dire…