springboot 配置跨域访问

news2024/11/30 6:10:47

什么是 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,
 // 携带cookie
  withCredentials: 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 {
    @Override
    public 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 {
    @Bean
    public 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";
 
    @Override
    public 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
     */
    @Bean
    public 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.coloradmin.cn/o/2250244.html

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

相关文章

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

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

【Linux】-学习笔记06

第二章、时间同步服务器 2.1时间同步服务器的使用 2.1.1系统时区时间的管理 timedatectl set-time "2024-02-13 10:41:55" ##设定系统时间 timedatectl list-timezones ##显示系统的所有时区 timedatectl set-timezone "Asia/Shangh…

Mac使用charles抓包

一、官网下载安装 二、配置Help--->SSL Proxying 有证书选择全部信任即可 三、设置系统代理&#xff0c;mac每次重启都需要选择&#xff0c;否则会没有数据 四、设置端口&#xff08;如果无法获取https&#xff09; 五、手机链接&#xff0c;从网页下载证书保存到手机&…

3d扫描建模产品开发-三维扫描检测蓝光检测

现当下&#xff0c;汽车制造、航空航天&#xff0c;还是消费电子、医疗器械&#xff0c;三维扫描检测与蓝光技术正以前所未有的精度和效率&#xff0c;推动着产品从概念到实物的快速转化。 三维扫描技术&#xff0c;简而言之&#xff0c;就是通过激光、结构光&#xff08;如蓝…

Hive中的基本数据类型和表的类型

Hive支持关系数据库中大多数据基本数据类型&#xff0c;同时还支持三种复杂类型。 示例&#xff1a; Hive表 创建表 – 直接建表法 create table t_page_view ( page_id bigint comment ‘页面ID’, page_name string comment ‘页面名称’, page_url string comment ‘页面…

Python PDF转JPG图片小工具

Python PDF转JPG图片小工具 1.简介 将单个pdf装换成jpg格式图片 Tip: 1、软件窗口默认最前端&#xff0c;不支持调整窗口大小&#xff1b; 2、可通过按钮选择PDF文件&#xff0c;也可以直接拖拽文件到窗口&#xff1b; 3、转换质量有5个档位&#xff0c;&#xff08;0.25&a…

剖析 SpringBoot 于夕阳红公寓管理系统架构搭建的核心作用

3 系统分析 本文作者在确定了研究的课题之后&#xff0c;从各大数字图书馆下载文献来阅读&#xff0c;并了解同类型的网站具备的大致功能&#xff0c;然后与本系统用户的实际需求结合进行分析&#xff0c;得出本系统要研究的具体功能与性能。虽然分析系统这一阶段性工作主要是确…

springboot336社区物资交易互助平台pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 社区物资交易互助平台设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff…

嵌入式linux系统中网络编程的具体实现

1.网络编程简介 要编写通过计算机网络通信的程序,首先要确定这些程序同通信的协议(protocol),在设计一个协议的细节之前,首先要分清程序是由哪个程序发起以及响应何时产生。 举例来说,一般认为WEB服务器程序是一个长时间运行的程序(守护进程deamon),它只在响应来自网…

vue3.0 根据富文本html页面生成压缩包(含视频在线地址、图片在线地址、前端截图、前端文档)

vue3.0生成压缩包&#xff08;含在线地址、前端截图、前端文档&#xff09; 需求描述效果开始下载插件包基本代码构造 点击下载按钮1.截图content元素&#xff0c;并转化为pdfcanvas putImageData、getImageDatagetImageData 获取指定矩形区域的像素信息putImageData 将这些数据…

由于导包而引发的错误

今天在调试时发现删除功能无论如何都无法实现&#xff0c;于是调试找到了mapper层的错误但不知道为什么报错。以下是报错信息。 Caused by: org.apache.ibatis.binding.BindingException: Parameter userIds not found. Available parameters are [arg0, collection, list]at o…

黑马2024AI+JavaWeb开发入门Day04-SpringBootWeb入门-HTTP协议-分层解耦-IOCDI飞书作业

视频地址&#xff1a;哔哩哔哩 讲义作业飞书地址&#xff1a;day04作业&#xff08;IOC&DI&#xff09; 作业很简单&#xff0c;主要是练习拆分为三层架构controller、service、dao&#xff0c;并基于IOC & DI进行解耦。 1、结构&#xff1a; 2、代码 网盘链接&…

【LeetCode: 145. 二叉树的后序遍历 + 栈】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

哈希表算法题

目录 题目一——1. 两数之和 - 力扣&#xff08;LeetCode&#xff09; 1.1.暴力解法1 1.2.暴力解法2 1.2.哈希表解法 题目二——面试题 01.02. 判定是否互为字符重排 - 力扣&#xff08;LeetCode&#xff09; 题目三——217. 存在重复元素 - 力扣&#xff08;LeetCode&…

Galaxy预测比特币期权活跃交易将持续至2027年,特朗普执政中期

随着比特币及其相关产品的交易量不断增加&#xff0c;加密货币市场的期权交易也迎来了前所未有的活跃。Galaxy Digital的交易团队指出&#xff0c;贝莱德IBIT ETF期权在美国股市的交易量已经创下了新纪录。首日交易量高达353,716份合约&#xff0c;几乎与2012年Facebook期权上线…

Java-GUI(登录界面示例)

简述&#xff1a; 步骤&#xff1a; (1)构造界面(将组件对象加入容器对象,注意&#xff1a;应设定对容器对象的布局策略&#xff09; (2)为界面加入事件响应处理(如单击按钮&#xff09; 实现&#xff1a; 两种方式实现&#xff0c;只有用户名为"admin"且密码为…

屏幕分辨率|尺寸|颜色深度指纹

一、前端通过window.screen接口获取屏幕分辨率 尺寸 颜色深度&#xff0c;横屏竖屏信息。 二、window.screen c接口实现&#xff1a; 1、third_party\blink\renderer\core\frame\screen.idl // https://drafts.csswg.org/cssom-view/#the-screen-interface[ExposedWindow ] …

【论文阅读】三平面相关与变体

文章目录 1. 【CVPR2023】Tri-Perspective View for Vision-Based 3D Semantic Occupancy Prediction动机可视化方法Pipeline 2. 【2023/08/31】PointOcc: Cylindrical Tri-Perspective View for Point-based 3D Semantic Occupancy Prediction动机&#xff08;针对雷达点云、与…

Java - JSR223规范解读_在JVM上实现多语言支持

文章目录 1. 概述2. 核心目标3. 支持的脚本语言4. 主要接口5. 脚本引擎的使用执行JavaScript脚本执行groovy脚本1. Groovy简介2. Groovy脚本示例3. 如何在Java中集成 Groovy4. 集成注意事项 6. 与Java集成7. 常见应用场景8. 优缺点9. 总结 1. 概述 JSR223&#xff08;Java Spe…

定时/延时任务-ScheduledThreadPoolExecutor的使用

文章目录 1. 概要2. 固定速率和固定延时2.1 固定速率2.2 固定延时 3. API 解释3.1 schedule3.2 固定延时 - scheduleWithFixedDelay3.2 固定速率 - scheduleWithFixedDelay 4. 小结 1. 概要 前三篇文章的地址&#xff1a; 定时/延时任务-自己实现一个简单的定时器定时/延时任…