开发者

SpringBoot使用CORS解决无法跨域访问问题的具体步骤

开发者 https://www.devze.com 2025-05-14 10:39 出处:网络 作者: 柯南二号
目录一、跨域问题二、跨域解决方案方法一:使用 @CrossOrigin 注解(适用于单个控制器或方法)方法二:全局配置 CORS(推荐)方法 2.1:实现 WebMvpythoncConfigurer方法三:通过 Filter 自
目录
  • 一、跨域问题
  • 二、跨域解决方案
    • 方法一:使用 @CrossOrigin 注解(适用于单个控制器或方法)
    • 方法二:全局配置 CORS(推荐)
      • 方法 2.1:实现 WebMvpythoncConfigurer
    • 方法三:通过 Filter 自定义 CORS 过滤器
      • 注意事项
      • 三、完整示例演示
        • 3.1 创建前端的node.js服务
          • 3.2 创建后端的springboot服务
            • 后端接口:HelloController.Java
            • 跨域配置:CorsConfig.java
        • 四、CORS详细解析
          • 逐项解释
            • allowedOrigins("http://localhost:3000")
            • allowedMethods("GET", "POST", "OPTIONS", "DELETE")
            • allowCredentials(true)
            • allowedHeaders("*")
            • maxAge(3600)
        • 总结配置最佳实践

          一、跨域问题

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

          跨域三种情况

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

          • 协议不同,如 http 和 https;
          • 域名不同;
          • 端口不同。

          也就是说,即使域名相同,如果一个使用的是 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-Contjavascriptrol-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
          

          SpringBoot使用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/,看到如下页面

          SpringBoot使用CORS解决无法跨域访问问题的具体步骤

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

          SpringBoot使用CORS解决无法跨域访问问题的具体步骤

          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服务BPZybckJNX以后,再去访问http://localhost:3000/,点击下面这个按钮,就会顺利拿到后端返回的数据

          SpringBoot使用CORS解决无法跨域访问问题的具体步骤

          四、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("*") // 允许所有请求头
          
          • 这表示只有 Authorization 和 Content-Type 这两个头部字段可以在跨域请求中被使用。

          http://www.devze.com

          例子:

          假设你想在请求中添加一个自定义的 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);                            // 可选,预检请求的缓存时间(单位秒)
          

          以上就是SpringBo编程客栈ot使用CORS解决无法跨域访问问题的具体步骤的详细内容,更多关于SpringBoot CORS跨域访问的资料请关注编程客栈(www.devze.com)其它相关文章!

          0

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          关注公众号