springboot跨域配置(cors)

这篇文章需要读者对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下来看下。

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值