【后端】SpringBoot用CORS解决无法跨域访问的问题

news2025/7/20 2:32:02

SpringBoot用CORS解决无法跨域访问的问题

一、跨域问题

跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。但这个保护机制也带来了新的问题,它的问题是给不同站点之间的正常调用,也带来的阻碍,那怎么解决这个问题呢?接下来我们一起来看。

跨域三种情况
在请求时,如果出现了以下情况中的任意一种,那么它就是跨域请求:

  1. 协议不同,如 http 和 https;
  2. 域名不同;
  3. 端口不同。

也就是说,即使域名相同,如果一个使用的是 http,另一个使用的是 https,那么它们也属于跨域访问。常见的跨域问题如下图所示:

场景编号当前页面地址(发起方)资源地址(目标方)是否跨域原因说明
1http://example.comhttp://example.com协议、域名、端口都相同
2http://example.comhttps://example.com协议不同
3http://example.comhttp://example.com:8080端口不同
4http://example.comhttp://sub.example.com子域名不同
5http://example.comhttp://example.org主域名不同
6http://example.comhttp://example.com/path/page仅路径不同,不构成跨域
7http://127.0.0.1http://localhost虽然都是本地,但域名不同
8http://localhost:3000http://localhost:4000端口不同
9http://a.example.comhttp://b.example.com子域名不同
10https://example.comhttps://example.com协议、域名、端口都相同

跨域的核心判断标准是:协议(scheme)、主机(host)、端口(port)三者中有任意一个不同即为跨域

二、跨域解决方案

在Spring Boot中,可以使用CORS(跨源资源共享,Cross-Origin Resource Sharing)来解决前端请求接口时出现的跨域问题。Spring Boot 提供了多种方式来配置 CORS,以下是几种常见的解决方式:


✅ 方法一:使用 @CrossOrigin 注解(适用于单个控制器或方法)

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*") // 允许所有来源跨域访问
public class MyController {

    @GetMapping("/data")
    public String getData() {
        return "Hello, CORS!";
    }
}

你也可以只在特定方法上添加:

@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/specific")
public String specificEndpoint() {
    return "This is CORS-enabled only for localhost:3000";
}

✅ 方法二:全局配置 CORS(推荐)

适合需要对整个项目的接口统一进行跨域配置。

方法 2.1:实现 WebMvcConfigurer

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsGlobalConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 匹配所有请求路径
                .allowedOrigins("*") // 允许所有来源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法
                .allowedHeaders("*") // 允许的请求头
                .allowCredentials(true) // 是否允许携带cookie
                .maxAge(3600); // 预检请求缓存时间(秒)
    }
}

allowedOrigins("*")allowCredentials(true) 不可同时使用,若需携带 Cookie,需指定具体域名。


✅ 方法三:通过 Filter 自定义 CORS 过滤器

适用于更底层的控制(不推荐,除非有特殊需求)。

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import java.io.IOException;

@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletResponse res = (HttpServletResponse) response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        res.setHeader("Access-Control-Allow-Headers", "*");
        res.setHeader("Access-Control-Allow-Credentials", "true");

        chain.doFilter(request, response);
    }
}

🔒 注意事项

  • 如果你使用了 spring-security,还需要在安全配置类中额外开启 CORS。
  • @CrossOrigin 默认支持 GET/HEAD/POST,其他请求方法如 PUT/DELETE 需要手动配置。
  • 在生产环境下,不要使用 "\*" 通配符,应明确指定允许的域名。

三、完整示例演示

写一个完整的node.js前端出现要跨域访问的时候,用SpringBoot的CORS()来解决跨域问题完整代码实例。

3.1 创建前端的node.js服务

创建目录

mkdir node-frontend && cd node-frontend

初始化

npm init -y

安装依赖

npm install express node-fetch cors

请添加图片描述

新建一个index.js文件

const express = require('express');
const fetch = require('node-fetch');
const cors = require('cors');

const app = express();
const PORT = 3000;

app.use(cors()); // 允许前端页面跨域访问(如果需要)

// 前端页面
app.get('/', (req, res) => {
  res.send(`
    <html>
      <body>
        <h2>Node.js Frontend</h2>
        <button onclick="callBackend()">Call Spring Boot API</button>
        <p id="result"></p>
        <script>
          function callBackend() {
            fetch('http://localhost:8080/api/hello', {
              method: 'GET',
              credentials: 'include'
            })
            .then(response => response.text())
            .then(data => {
              document.getElementById('result').innerText = data;
            })
            .catch(error => console.error('Error:', error));
          }
        </script>
      </body>
    </html>
  `);
});


app.listen(PORT, () => {
    console.log(`Frontend running at http://localhost:${PORT}`);
}); 

启动node.js的服务

cd node-frontend
node index.js

访问http://localhost:3000/,看到如下页面

请添加图片描述

在没有配置这个的时候,通过F12查看控制台,点击按钮会提示如下信息:

请添加图片描述

3.2 创建后端的springboot服务
后端接口:HelloController.java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from Spring Boot!";
    }
}
跨域配置:CorsConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000") // 只允许 node 前端
                .allowedMethods("GET", "POST", "OPTIONS", "DELETE")
                .allowCredentials(true);
    }
}

启动springboot和node.js服务以后,再去访问http://localhost:3000/,点击下面这个按钮,就会顺利拿到后端返回的数据

请添加图片描述

四、CORS详细解析

下面是对提到的 Spring Boot 跨域配置中每一项的详细解释:

registry.addMapping("/**")
        .allowedOrigins("http://localhost:3000") // 只允许来自该源的跨域请求
        .allowedMethods("GET", "POST", "OPTIONS", "DELETE") // 允许的 HTTP 方法
        .allowCredentials(true); // 允许携带凭证(如 Cookie)

🔍 逐项解释

addMapping("/**")
  • 作用:设置哪些 URL 路径可以被跨域请求访问。
  • "/**" 表示对 所有接口 开启跨域支持。
  • 示例:/api/hello/user/info 等都受此配置控制。

allowedOrigins("http://localhost:3000")
  • 作用:设置允许跨域请求的来源(origin),即前端运行的地址。
  • 浏览器发起跨域请求时会带上 Origin 请求头,Spring 会检查它是否在这个列表中。
  • 示例:
    • 当前设置只允许从 http://localhost:3000 发起的跨域请求。
    • 如果你用的是 React/Vite/Node.js 前端开发服务器,就很可能是这个端口。

⚠️ 注意:如果你使用 allowedOrigins("*") 通配所有来源,就不能使用 allowCredentials(true),否则浏览器会拒绝响应。


allowedMethods("GET", "POST", "OPTIONS", "DELETE")
  • 作用:指定允许前端发起的 HTTP 方法。
  • 常见的跨域请求方法包括:
    • GET:获取资源
    • POST:提交数据
    • OPTIONS:预检请求(preflight),浏览器用于询问服务器是否允许跨域
    • DELETE:删除资源
  • 你也可以加上 "PUT""PATCH" 等方法,取决于你的 API 接口支持哪些。

allowCredentials(true)
  • 作用:允许前端在跨域请求中携带认证信息(如 Cookie、HTTP 认证头)。

  • 如果你希望用户登录后发送带 cookie 的请求(比如 JSESSIONID),必须设置为 true

  • 配合前端的配置使用:

    fetch("http://localhost:8080/api/hello", {
      credentials: "include"  // 必须设置这项才能带上 Cookie
    });
    

⚠️ **关键点:**当 allowCredentials(true) 时,allowedOrigins("*") 是不允许的,必须指定明确的 Origin。


allowedHeaders("*")
  • 作用:指定哪些请求头(headers)是允许的跨域请求中使用的。
  • 默认情况下,浏览器不允许跨域请求携带自定义请求头。使用 allowedHeaders 可以明确告诉 Spring Boot 服务器,允许哪些请求头携带过来。

示例:

.allowedHeaders("*") // 允许所有请求头
  • *:表示允许所有请求头。

  • 如果你只希望允许特定的请求头,可以设置具体的头部字段:

    .allowedHeaders("Authorization", "Content-Type")
    

    这表示只有 AuthorizationContent-Type 这两个头部字段可以在跨域请求中被使用。

例子:

假设你想在请求中添加一个自定义的 X-Auth-Token 头部字段来验证身份,那么你需要在服务器端配置允许这个头部:

.allowedHeaders("X-Auth-Token")

maxAge(3600)
  • 作用:指定浏览器在进行 预检请求(preflight) 时,缓存响应的最大时间(单位:秒)。
  • 预检请求是指在实际发起跨域请求之前,浏览器会先发送一个 OPTIONS 请求到目标服务器,询问是否允许跨域操作。服务器响应该请求后,浏览器会根据返回的信息决定是否继续发送实际的请求。
示例:
.maxAge(3600)  // 允许预检请求的缓存时间为 3600 秒(即 1 小时)
  • 实际效果:如果预检请求成功,浏览器会缓存该响应 3600 秒,直到缓存过期才重新发送预检请求。如果你有大量的跨域请求,增加缓存时间能够减少预检请求的频繁发起,提高性能。
例子:
  • 如果你经常发送跨域请求,而预检请求(OPTIONS)非常频繁,你可以通过增加 maxAge 来减少预检请求的次数,从而提高性能。
  • maxAge(3600) 表示预检请求的响应将在 1 小时内缓存,不会再发送新的预检请求。

综合配置

根据上述的解释,完整的跨域配置代码可能是这样的:

registry.addMapping("/**")
        .allowedOrigins("http://localhost:3000") // 只允许来自该源的跨域请求
        .allowedMethods("GET", "POST", "OPTIONS", "PUT", "DELETE") // 允许的 HTTP 方法
        .allowedHeaders("Content-Type", "Authorization", "X-Auth-Token") // 允许的请求头
        .allowCredentials(true) // 允许携带凭证(如 Cookie)
        .maxAge(3600); // 预检请求缓存 1 小时

✅ 总结配置最佳实践

registry.addMapping("/**")
        .allowedOrigins("http://localhost:3000")  // 推荐明确指定前端地址
        .allowedMethods("GET", "POST", "OPTIONS", "PUT", "DELETE")
        .allowedHeaders("*")                      // 可选,允许前端发送的自定义 Header
        .allowCredentials(true)
        .maxAge(3600);                            // 可选,预检请求的缓存时间(单位秒)

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

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

相关文章

MySQL 8.0(主从复制)

MySQL 8.0 的 主从复制&#xff08;Master-Slave Replication&#xff09; 是一种数据库高可用和数据备份的核心技术&#xff0c;下面用 一、什么是主从复制&#xff1f; 就像公司的「领导-秘书」分工&#xff1a; 主库&#xff08;Master&#xff09;&#xff1a;负责处理所…

TCPIP详解 卷1协议 十 用户数据报协议和IP分片

10.1——用户数据报协议和 IP 分片 UDP是一种保留消息边界的简单的面向数据报的传输层协议。它不提供差错纠正、队列管理、重复消除、流量控制和拥塞控制。它提供差错检测&#xff0c;包含我们在传输层中碰到的第一个真实的端到端&#xff08;end-to-end&#xff09;校验和。这…

finebi使用资源迁移无法导入资源,解决方法

finebi使用资源迁移无法导入资源&#xff0c;解决方法 最近在使用finebi开发finebi报表&#xff0c;报表开发之后&#xff0c;从一台电脑将资源导入另一台电脑后&#xff0c;出现不允许导入的提示&#xff0c;如下&#xff1a; 原因&#xff1a; 两个finebi的管理员名称不一致…

分布式锁redisson的中断操作

1、先贴代码 RequestMapping(value "/update", method RequestMethod.POST)ResponseBodypublic Result update(RequestBody Employee employee) { // 修改数据库&#xff08;存在线程不安全 需要使用redison设置分布式锁 防止被修改&#xff09; // 设…

Docker:安装配置教程(最新版本)

文章目录 一、前言二、具体操作2.1 卸载 Docker (可选)2.2 重新安装&#xff08;使用清华大学镜像&#xff09;2.3 配置轩辕镜像加速2.4 Docker 基本命名2.5 测试是否成功 三、结语 一、前言 Docker 是一种容器化技术&#xff0c;在软件开发和部署中得到广泛的应用&#xff0c…

neo4j官方示例

目录 一、准备数据 1.执行查看结果 二、操作 1.find 单个节点 2.同上&#xff0c;已某个属性去查询 3. 指定查询个数 4.条件查询 5.查询某个人出演的电影汇总 6.查询tom出演的电影中&#xff0c;还有其他演员的信息。 7.查询跟电影(Cloud Atlas)有关的演员&#xff0…

前端自学入门:HTML 基础详解与学习路线指引

在互联网的浪潮中&#xff0c;前端开发如同构建数字世界的基石&#xff0c;而 HTML 则是前端开发的 “入场券”。对于许多渴望踏入前端领域的初学者而言&#xff0c;HTML 入门是首要挑战。本指南将以清晰易懂的方式&#xff0c;带大家深入了解 HTML 基础&#xff0c;并梳理前端…

vue实现与后台springboot传递数据【传值/取值 Axios 】

vue实现与后台springboot传递数据【传值/取值】 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是node.js和vue的使用。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性。【帮帮志系列文章】&#xff1a;每…

【英语笔记(三)】介绍谓语动词的分类,初步讲解四种基本状态:一般、进行、完成、完成进行

1. 五大类谓语动词 2. 谓语动词分类 3. 动词时间 过去--------------------------现在-----------------------未来 3. 动词状态 3.1 进行状态 3.2 完成状态 3.3 完成进行状态 3.4 一般状态 4. 时间 状态 名称说明例句现在现在现在现在进行时态现在某物正在做什么事情一只…

【Python】让Selenium 像Beautifulsoup一样,用解析HTML 结构的方式提取元素!

我在使用selenium的find_element的方式去获取网页元素&#xff0c;一般通过xpath、css_selector、class_name的方式去获取元素的绝对位置。 但是有时候如果网页多了一些弹窗或者啥之类的&#xff0c;绝对位置会发生变化&#xff0c;使用xpath等方法&#xff0c;需要经常变动。…

2025 后端自学UNIAPP【项目实战:旅游项目】3、API接口请求封装,封装后的简单测试以及实际使用

一、创建请求封装目录 选中自己的项目&#xff0c;右键鼠标---->新建---->目录---->名字自定义【我的是api】 二、创建两个js封装文件 选中封装的目录&#xff0c;右键鼠标---->新建---->js文件---->名字自定义【我的两个js文件分别是my_http和my_api】 三…

Ascend的aclgraph(二)_npu_backend中还有些什么秘密?

1 _npu_backend 文章还是从代码开始 import torch_npu, torchair config torchair.CompilerConfig() # 设置图下沉执行模式 config.mode "reduce-overhead" npu_backend torchair.get_npu_backend(compiler_configconfig) opt_model torch.compile(model, back…

ventoy安全启动怎么选_ventoy安全启动支持是开还是关

ventoy安全启动怎么选&#xff1f;Ventoy新一代多系统启动U盘解决方案。国产开源U盘启动制作工具&#xff0c;支持Legacy BIOS和UEFI模式&#xff0c;理论上几乎支持任何ISO镜像文件&#xff0c;支持加载多个不同类型的ISO文件启动&#xff0c;无需反复地格式化U盘&#xff0c;…

CC53.【C++ Cont】二分查找的普通模版

目录 1.知识回顾 2.关键点 特点 三个模版 普通的模版(有局限) 以LeetCode上的一道题为例:704. 二分查找 分析 引入二段性:分两段,舍一段,操作另一段(这个是二分查找的本质!) 代码 提交结果 当然也可以使用随机数来分两段 普通模版总结 1.知识回顾 之前在C语言专栏…

【优选算法 | 链表】链表操作技巧:常见算法

算法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;双指针滑动窗口二分查找前缀和位运算模拟 链表是一种灵活的数据结构&#xff0c;广泛用于需要频繁插入和删除的场景。掌握链表的常见操作技巧&#xff0c;如插入、删除、翻转和合并等&#xff0c;能帮助开发者更…

w~大模型~合集30

我自己的原文哦~ https://blog.51cto.com/whaosoft/13284996 #VideoMamba 视频理解因大量时空冗余和复杂时空依赖&#xff0c;同时克服两个问题难度巨大&#xff0c;CNN 和 Transformer 及 Uniformer 都难以胜任&#xff0c;Mamba 是个好思路&#xff0c;让我们看看本文是…

PBR材质-Unity/Blender/UE

目录 前言&#xff1a; 一、Unity&#xff1a; 二、Blender&#xff1a; 三、UE&#xff1a; 四、全家福&#xff1a; 五、后记&#xff1a; 前言&#xff1a; PBR流程作为表达物理效果的经典方式&#xff0c;很值得一学。纹理贴图使用的是上一期的Textures | cgbookcas…

websocketpp 安装及使用

介绍 WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的消息推送机制。 传统的 web 程序都是属于 "一问一答" 的形式&#xff0c;即客户端给服务器发送了一个 HTTP 请求&#xff0c;服务器给客户端返回一个 HTTP 响应。这种情况下服务器是属于被动…

第8章-2 查询执行的基础

上一篇&#xff1a;《第8章-1 查询性能优化-优化数据访问》&#xff0c;接着来了解查询执行的过程&#xff0c;这个对sql执行有个更直观的了解。 查询执行的基础 当希望MySQL能够以更高的性能运行查询时&#xff0c;最好的办法就是弄清楚MySQL是如何优化和执行查询的。一旦理解…

java面试OOM汇总

在正式 Minor GC 前&#xff0c;JVM 会先检查新生代中对象&#xff0c;是比老年代中剩余空间大还是小。假如 Minor GC之后 Survivor 区放不下剩余对象&#xff0c;这些对象就要进入老年代 老年代剩余空间大于新生代中的对象大小&#xff0c;那就直接 Minor GC&#xff0c; GC 完…