springboot跨域配置(cors)

本文深入探讨SpringBoot中CORS(跨来源资源共享)的概念与实现,通过实例讲解如何配置跨域请求,确保前后端分离项目顺利运行。同时,提供了一个自定义CORS解决方案,适用于非SpringBoot架构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这篇文章需要读者对nginx和springboot相关的知识有一定了解,起码入过门。

一、什么是跨域(cors)?

关于跨域的介绍网上有很多,我参考跨域资源共享 CORS 详解,阮老师写的很到位,我们来做个简单的总结

1、首先我们知道ajax只能同源使用限制,这是跨域问题产生的原因,我们前端在ajax中请求了跨域资源。

2、然后才有了cors,cors允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制

3、cors只和浏览器、服务端(我们的springboot项目)有关系,浏览器会自动判断是否跨域并在请求头加上相应的信息(这部分在我的落地代码里会在谈到,先不展开),因此cors的关键就是服务端的设置了。

二、web服务跨域基本实现

我们现在知道了跨域只需要关心服务端配置就可以了,使用springboot架构来做跨域配置非常简单,可参看 springboot文档

我截了一段代码, @RequestMapping(value = {"/whatever/cors"}) 这个接口可以允许来自http://local.sveqxiu.net域名的跨域请求。

@Configuration
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/whatever/cors").allowedOrigins("http://local.sveqxiu.net");
            }
        };
    }
}

前端代码如下:(前端代码基本没用到,如果你不想自己动手配置nginx验证的话)

<html>
<body>
	<style></style>
</body>
<!DOCTYPE html>
<html>
<head>
	<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
		$.ajax({
			url:'http://localhost:8090/whatever/cors',
			success:function(data) {
				console.info(data);
			}
		});
});
</script>
</head>
<body>
<p>cors跨域设置。</p>
</body>
</html>

我使用的ubuntu系统,可使用curl来验证跨域, curl -H 可模拟指定Access-Control-Allow-Origin: http://local.sveqxiu.net,这时候因为在代码里配置了/whatever/cors接口允许来自http://local.sveqxiu.net的跨域请求。所以请求返回200

suibing@suibing-ThinkPad-T430:~/work/ws/muti-module$ curl -I -H "origin: http://local.sveqxiu.net"  "http://localhost:8090/whatever/cors"
HTTP/1.1 200 
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://local.sveqxiu.net
Content-Type: text/plain;charset=UTF-8
Content-Length: 13
Date: Mon, 28 Jan 2019 09:01:26 GMT

suibing@suibing-ThinkPad-T430:~/work/ws/muti-module$ 

我们修改MyConfiguration类的代码改变cors配置"http://local.sveqxiu.net" 为 "http://test.net" 再次测试,结果如下,返回403,这里403是跨域,如果在浏览器模拟的话 错误信息是 【js.html:1 Failed to load http://localhost:8090/whatever/cors: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://local.sveqxiu.net' is therefore not allowed access.】(为了简单所以使用了curl做测试,请耐心往下看,后面会使用nginx来模拟浏览器真实的情况)

suibing@suibing-ThinkPad-T430:~/work/ws/muti-module$ curl -I -H "origin: http://local.sveqxiu.net"  "http://localhost:8090/whatever/cors"
HTTP/1.1 403 
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Length: 20
Date: Mon, 28 Jan 2019 09:11:19 GMT

suibing@suibing-ThinkPad-T430:~/work/ws/muti-module$ 

正确和错误的情况我们都验证了,那如果我们不配置跨域会怎么样呢? 让我们来试试,把MyConfiguration类的@Configuration注解去掉,这便取消了cors配置,再来测试,结果如下,返回了200,但是和配置了cors的时候少返回了些头信息。这说明了如果服务端不做cors配置是可以接受来自任何域的请求并做成响应的。假如服务没有跨域限制会出现什么问题?项目的可接受来自任何人的访问,数据安全岌岌可危,有兴趣的可参看跨域资源共享(CORS)安全性浅析,回到正题,服务端不做跨域配置,虽然请求成功了但是浏览器可不同意呢?先看结论:如下图,请求返回200,浏览器报错,页面不会展示资源,但是在response里已经返回了数据了,这是非常不安全的。

要验证以上内容,需要配置nginx服务, nginx安装什么的自己去搞吧, 安装完之后准备一个文件发布html的配置文件(当然只要能把静态资源发布出去就可以了iis啥的都可以)

前端nginx配置文件如下:

server {
  listen 80;  #web项目监听80端口
  server_name local.sveqxiu.net;#需要配置hosts 127.0.0.1 local.sveqxiu.net
  location /h2 {
        root /home/suibing/Documents/; #放静态文件的url。
  }

}

----------------------------------------------------------------  分割线  ----------------------------------------------------------------------------------------

springboot配置cors以及验证结束了,但是如果没有spring架构,我们如何实现自己的cors呢?

根据原理,浏览器跨域请求分为简单请求和非简单请求,简单请求浏览器会给头信息加上Origin字段,非简单请求会发”预检“请求,头信息包括Origin、Access-Control-Request-Method和Access-Control-Request-Header,依据这些信息来辨别请求类型,然后根据不同类型做处理就可以了,如今springboot架构已经非常善了,为什么还要重复造轮子呢?就我而言,肯定是兴趣所在,springboot固然完善,但企业级的应用却非常复杂,比如公司一级域名下有成百上千个二级域名,而二级域名都允许跨域的话,每个开发团队都去配置一遍无疑是很多重复的工作量,另外,如果想动态配置跨域域名,原生的技术好像是无法实现呢

下面一个简单的demo ,只要把 cors方法里的内容封装到一个filter就可以实现全局的过滤配置了,我这里只处理了简单请求demo代码如下

@Controller
public class CORSController {

    private List<String> allowOrigin = new ArrayList<String>()
    {
        {
         add("http://local.sveqxiu.net");
         add("http://h2.veqxiu.net");
        }
    };
    @RequestMapping(value = {"/whatever/cors"})
    @ResponseBody
    public String cors(HttpServletRequest request, HttpServletResponse response) {
        String origin = request.getHeader("Origin");
        String method = request.getHeader("Access-Control-Request-Method");
        String header = request.getHeader("Access-Control-Request-Header");
        // 是简单跨域请求
        if (!StringUtils.isEmpty(origin) && StringUtils.isEmpty(method) && StringUtils.isEmpty(header)) {
            if (allowOrigin.contains(origin)) {
                response.addHeader("Access-Control-Allow-Origin", origin);
                response.addHeader("Access-Control-Allow-Credentials", "true");
            } else {
                return "denied origin" + origin;
            }
        }
        // 复杂跨域请求
        if (!StringUtils.isEmpty(origin) && !StringUtils.isEmpty(method) && !StringUtils.isEmpty(header)) {

        }
        return "whatever cors";
    }

}

我结合springboot开发了一款可外部化配置的cors框架,代码在github上 https://github.com/superbing09/cors , 有兴趣的朋友可以pull下来看下。

 

### 配置CORS以允许请求 在Spring Boot应用程序中,可以通过多种方式来配置CORS源资源共享),以便处理来自不同名的HTTP请求。 #### 使用`@CrossOrigin`注解 对于简单的场景,在控制器方法上使用`@CrossOrigin`注解是一种便捷的方式。这不需要额外的具体配置就能生效[^1]: ```java @RestController public class MyController { @CrossOrigin(origins = "http://example.com") @GetMapping("/hello") public String hello() { return "Hello World"; } } ``` 此代码片段展示了如何通过指定特定原点来限定哪些网站可以访问该端点;也可以设置为通配符(*)表示接受所有来源的请求。 #### 全局CORS配置 当需要更复杂的控制时,则应该考虑全局范围内的CORS策略定义。可以在应用启动类或任意@Configuration标记下的Java Config文件里实现WebMvcConfigurer接口并重写addCorsMappings方法: ```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 WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 对所有的路径都有效 .allowedOrigins("*") // 允许任何来源发起请求 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS"); // 支持的方法列表 } } ``` 上述例子设置了开放式的CORS规则给整个API服务[^2]。 #### 结合Spring Security使用 如果有集成Spring Security框架的情况,还需要特别注意开启CORS支持。可在Security配置中加入如下XML声明: ```xml <http> <!-- 默认采用Spring MVC内置的CORS机制 --> <cors /> </http> ``` 或者基于Java Config的形式完成相同功能: ```java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final CorsConfigurationSource corsConfigurationSource; @Bean CorsConfigurationSource corsConfigurationSource() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOriginPattern("*"); config.setMaxAge(3600L); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return source; } @Override protected void configure(HttpSecurity http) throws Exception { http.cors().configurationSource(corsConfigurationSource).and() ... } } ``` 这段代码实现了更加细粒度的安全性和灵活性管理的同时也确保了CORS的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值