文档章节

SpringBoot 实现前后端分离的跨域访问(CORS)

SpringForAll
 SpringForAll
发布于 2017/11/14 09:58
字数 1707
阅读 808
收藏 84
点赞 0
评论 4

社区原文链接:http://www.spring4all.com/article/177

序言:跨域资源共享向来都是热门的需求,使用CORS可以帮助我们快速实现跨域访问,只需在服务端进行授权即可,无需在前端添加额外设置,比传统的JSONP跨域更安全和便捷。

#一、基本介绍

简单来说,CORS是一种访问机制,英文全称是Cross-Origin Resource Sharing,即我们常说的跨域资源共享,通过在服务器端设置响应头,把发起跨域的原始域名添加到Access-Control-Allow-Origin 即可。

#1. CORS工作原理

CORS实现跨域访问并不是一蹴而就的,需要借助浏览器的支持,从原理题图我们可以清楚看到,简单的请求(通常指GET/POST/HEAD方式,并没有去增加额外的请求头信息)直接创建了跨域请求的XHR对象,而复杂的请求则要求先发送一个"预检"请求,待服务器批准后才能真正发起跨域访问请求。

来自维基百科

根据官方文档W3C规范-CORS 的描述,目前CORS使用了如下头部信息:

注:请求头信息由浏览器检测到跨域自动添加,无需过多干预,重点放在Response headers,它可以帮助我们在服务器进行跨域授权,例如允许哪些原始域可放行,是否需要携带Cookie信息等。

#2. Request Headers(请求头)

  • Origin

    表示跨域请求的原始域。
  • Access-Control-Request-Method

    表示跨域请求的方式。(如GET/POST)
  • Access-Control-Request-Headers

    表示跨域请求的请求头信息。

#3. Response headers(响应头 )

  • Access-Control-Allow-Origin

    表示允许哪些原始域进行跨域访问。(字符数组)
  • Access-Control-Allow-Credentials

    表示是否允许客户端获取用户凭据。(布尔类型) 使用场景:例如现在从浏览器发起跨域请求,并且要附带Cookie信息给服务器。则必须具备两个条件:**1. 浏览器端:**发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。 **2.服务器端:**设置Access-Control-Allow-Credentials为true。两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。正确姿势如下:

  • Access-Control-Allow-Methods

    表示跨域请求的方式的允许范围。(例如只授权GET/POST)
  • Access-Control-Allow-Headers

    表示跨域请求的头部的允许范围。
  • Access-Control-Expose-Headers

    表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息)
  • Access-Control-Max-Age

    表示预检请求 [Preflight Request] 的最大缓存时间。

#二、CORS实现跨域访问

#授权方式

  • 方式1:返回新的CorsFilter
  • 方式2:重写WebMvcConfigurer
  • 方式3:使用注解(@CrossOrigin)
  • 方式4:手工设置响应头(HttpServletResponse )

注:CorsFilter / WebMvcConfigurer / @CrossOrigin 需要SpringMVC 4.2 以上的版本才支持,对应SpringBoot 1.3 版本以上都支持这些CORS特性。不过,使用SpringMVC4.2 以下版本的小伙伴也不用慌,直接使用方式4通过手工添加响应头来授权CORS跨域访问也是可以的。附:在SpringBoot 1.2.8 + SpringMVC 4.1.9 亲测成功。

注:方式1和方式2属于全局CORS配置,方式3和方式4属于局部CORS配置。如果使用了局部跨域是会覆盖全局跨域的规则,所以可以通过@CrossOrigin注解来进行细粒度更高的跨域资源控制。

#1. 返回新的CorsFilter(全局跨域)

在任意配置类,返回一个新的CorsFilter Bean,并添加映射路径和具体的CORS配置信息。

package com.hehe.yyweb.config;

@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config = new CorsConfiguration();
          //放行哪些原始域
          config.addAllowedOrigin("*");
          //是否发送Cookie信息
          config.setAllowCredentials(true);
          //放行哪些原始域(请求方式)
          config.addAllowedMethod("*");
          //放行哪些原始域(头部信息)
          config.addAllowedHeader("*");
          //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
          config.addExposedHeader("*");

        //2.添加映射路径
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}

#2. 重写WebMvcConfigurer(全局跨域)

在任意配置类,返回一个新的WebMvcConfigurer Bean,并重写其提供的跨域请求处理的接口,目的是添加映射路径和具体的CORS配置信息。

package com.hehe.yyweb.config;

@Configuration
public class GlobalCorsConfig {
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            //重写父类提供的跨域请求处理的接口
            public void addCorsMappings(CorsRegistry registry) {
                //添加映射路径
                registry.addMapping("/**")
                        //放行哪些原始域
                        .allowedOrigins("*")
                        //是否发送Cookie信息
                        .allowCredentials(true)
                        //放行哪些原始域(请求方式)
                        .allowedMethods("GET","POST", "PUT", "DELETE")
                        //放行哪些原始域(头部信息)
                        .allowedHeaders("*")
                        //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
                        .exposedHeaders("Header1", "Header2");
            }
        };
    }
}

#3. 使用注解(局部跨域)

在方法上(@RequestMapping)使用注解 @CrossOrigin

	@RequestMapping("/hello")
	@ResponseBody
	@CrossOrigin("http://localhost:8080") 
	public String index( ){
		return "Hello World";
	}

或者在控制器(@Controller)上使用注解 @CrossOrigin

@Controller
@CrossOrigin(origins = "http://xx-domain.com", maxAge = 3600)
public class AccountController {

    @RequestMapping("/hello")
    @ResponseBody
    public String index( ){
        return "Hello World";
    }
}

#4. 手工设置响应头(局部跨域 ) 使用HttpServletResponse对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里Origin的值也可以设置为"*" ,表示全部放行。

	@RequestMapping("/hello")
	@ResponseBody
	public String index(HttpServletResponse response){
		response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
		return "Hello World";
	}

#三、测试跨域访问

首先使用 Spring Initializr 快速构建一个Maven工程,什么都不用改,在static目录下,添加一个页面:index.html 来模拟跨域访问。目标地址: http://localhost:8090/hello

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Page Index</title>
</head>
<body>
<h2>前台系统</h2>
<p id="info"></p>
</body>
<script src="webjars/jquery/3.2.1/jquery.js"></script>
<script>
    $.ajax({
        url: 'http://localhost:8090/hello',
        type: "POST",
        success: function (data) {
            $("#info").html("跨域访问成功:"+data);
        },
        error: function (data) {
            $("#info").html("跨域失败!!");
        }
    })
</script>
</html>

然后创建另一个工程,在Root Package添加Config目录并创建配置类来开启全局CORS。

package com.hehe.yyweb.config;

@Configuration
public class GlobalCorsConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**");
            }
        };
    }
}

接着,简单编写一个Rest接口 ,并指定应用端口为8090。

package com.hehe.yyweb;

@SpringBootApplication
@RestController
public class YyWebApplication {

    @Bean
    public TomcatServletWebServerFactory tomcat() {
        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();
        tomcatFactory.setPort(8090); //默认启动8090端口
        return tomcatFactory;
    }

    @RequestMapping("/hello")
    public String index() {
        return "Hello World";
    }

    public static void main(String[] args) {
        SpringApplication.run(YyWebApplication.class, args);
    }
}

最后分别启动两个应用,然后在浏览器访问:http://localhost:8080/index.html ,可以正常接收JSON数据,说明跨域访问成功!!

尝试把全局CORS关闭,或者没有单独在方法或类上授权跨域,再次访问:http://localhost:8080/index.html 时会看到跨域请求失败!!

#四、源码和文档

Github源码:SpringBoot-Cross-Orgin

专题地址:SpringBoot 从入门到上瘾

规范文档:W3C规范-CORS

传统文档:SpringMVC-CORS 使用手册

推荐阅读:跨域资源共享 CORS 详解 - 阮一峰

© 著作权归作者所有

共有 人打赏支持
SpringForAll
粉丝 95
博文 11
码字总数 22839
作品 0
加载中

评论(4)

iehyou
iehyou

引用来自“八一菜刀”的评论

比传统的JSONP跨域更安全?
怎么个安全法呢?
可以post无限长度的数据
罗格林
罗格林
响应头里面只有 Access-Control-Allow-Origin 才是对所有请求方法都应该提供的,其他的,比如 Access-Control-Request-Headers 等只有 Option 请求才需要提供.

在 ActFramework 里面最简单的打开 CORS 方式就是配置文件加上 cors=true. 也可配置其他响应头, 当然 Act 只会针对 Option 请求返回 Access-Control-Allow-Origin 以外的 CORS 响应.
夜辰
夜辰
我们直接用nginx代理的。
八一菜刀
八一菜刀
比传统的JSONP跨域更安全?
怎么个安全法呢?
恒宇少年/spring-boot-chapter

简书整套文档以及源码解析 专题 专题名称 专题描述 001 Spring Boot 核心技术 讲解SpringBoot一些企业级层面的核心组件 002 Spring Cloud 核心技术 对Spring Cloud核心技术全面讲解 003 Quer...

恒宇少年 ⋅ 04/19 ⋅ 0

SpringBoot笔记(五)模板引擎thymeleaf和freemarker

SpringBoot本来不应该关注这块,但是既然都学了,就看看吧 SpringBoot属于前后端分离的微服务框架,默认的模板引擎是thymeleaf,虽然也能支持JSP,但是比较麻烦,另外freemarker也是SpringB...

世外大帝 ⋅ 04/25 ⋅ 0

用IDEA搭建springboot+thymleaf+mybatis(附分页方法)

参考thymleaf官方网址: 现在主流的微服务springboot配合H5开发效率极快。也符合现在前后端分离的开发方式。 thymleaf作为页面模板框架,可以更好的处理Controller和html的关系。 具体搭建过程...

HaleyLiu ⋅ 05/17 ⋅ 0

如何在本地部署vue+springboot前后端分离应用

今天想在windows本地搭建一个服务器跑整个vue+springboot项目,但始终访问不到后端接口,网上介绍这方面的博客也很少,现在我将我的搭建过程与大家分享一下。 我们知道,在平时的开发过程中,...

为了美好的明天 ⋅ 05/14 ⋅ 0

springboot + shiro 权限注解、请求乱码解决、统一异常处理

springboot + shiro 权限注解、请求乱码解决、统一异常处理 前篇 后台权限管理系统 相关: spring boot + mybatis + layui + shiro后台权限管理系统 springboot + shiro之登录人数限制、登录...

wyait ⋅ 06/06 ⋅ 0

用IDEA搭建springboot+thymleaf+mybatis+pageHelper搭建框架

参考thymleaf官方网址: 现在主流的微服务springboot配合H5开发效率极快。也符合现在前后端分离的开发方式。 thymleaf作为页面模板框架,可以更好的处理Controller和html的关系。 具体搭建过程...

HaleyLiu ⋅ 05/16 ⋅ 0

SpringBoot使用WebJars

本人主要做的是java,但是从第一份工作开始,就一直在做一个写前端又写后端的程序员,相信很多朋友和我一样,不仅要会后台代码,还要懂得很多的前端代码,例如javascipt和css样式。 本文就为...

dalaoyang ⋅ 03/22 ⋅ 0

基于SpringBoot 2的管理后台系统

本文demo下载:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=1062 一个基于SpringBoot 2 的管理后台系统,包含了用户管理,组织机构管理,角色管理,功能点管理,菜...

智慧点点 ⋅ 04/23 ⋅ 0

SpringBoot 整合(六)Security & Oauth2.0(完整篇)

1. 快速实现篇(实现最基本的登录): SpringSecurity 快速实现项目 2. 企业级封装篇 我的 Spring Security 文集 SpringBoot 整合 Security(一)实现用户认证并判断返回json还是view SpringBo...

FantJ ⋅ 05/22 ⋅ 0

Docker下ELK三部曲之二:细说开发

本章是《Docker下ELK三部曲》的第二篇,之前的《Docker下ELK三部曲之一:极速体验》部署了ELK,还有一个web应用可以将日志上报到ELK,然后在Kibana提供的页面查询到了日志,今天我们一起深入...

boling_cavalry ⋅ 04/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

ORM——使用spring jpa data实现逻辑删除

前言 在业务中是忌讳物理删除数据的,数据的这个对于一个IT公司可以说是最核心的资产,如果删除直接就物理删除,无疑是对核心资产的不重视,可能扯的比较远,本文最主要是想通过spring jpa ...

alexzhu592 ⋅ 31分钟前 ⋅ 0

代码快速“检”“修”不是梦,阿里云MaxCompute Studio 2.9.0 新版本发布

摘要: 阿里云MaxCompute Studio 2.9.0 新版本发布,此次发布的新版本,在原有功能的基础上增加了新功能,分别是支持代码检查和快速修复;支持graph开发及调试。 近日,阿里云大数据计算服务...

猫耳m ⋅ 33分钟前 ⋅ 0

CDN caching

Incapsula应用感知CDN使用智能分析和频率分析来动态缓存内容,并最大限度地提高效率。确保可直接从RAM获取最常访问的资源,而不依赖于较慢的访问机制。 1、 静态内容缓存 Incapsula缓存静态内...

上树的熊 ⋅ 34分钟前 ⋅ 0

代码快速“检”“修”不是梦,阿里云MaxCompute Studio 2.9.0 新版本发布

摘要: 阿里云MaxCompute Studio 2.9.0 新版本发布,此次发布的新版本,在原有功能的基础上增加了新功能,分别是支持代码检查和快速修复;支持graph开发及调试。 近日,阿里云大数据计算服务...

阿里云云栖社区 ⋅ 38分钟前 ⋅ 0

密码协议(一)协议概述

区块链兄弟社区,区块链技术专业问答先行者,中国区块链技术爱好者聚集地 作者:于中阳 来源:区块链兄弟 原文链接:http://www.blockchainbrother.com/article/86 著权归作者所有。商业转载...

-区块链兄弟- ⋅ 42分钟前 ⋅ 0

vim基础-一般模式

vim编辑器是vi编辑器的升级版本,支持颜色显示。使用yum安装vim-enhanced包。 /etc下的配置文件使用vim编辑可显示颜色,/etc下相同文件拷贝到其他目录不显示颜色。 三种模式:一般模式,编辑...

ZHENG-JY ⋅ 43分钟前 ⋅ 0

spring boot

https://www.cnblogs.com/EasonJim/p/7609911.html

vshcxl ⋅ 47分钟前 ⋅ 0

数据库中常说的steal和force到底是什么?

时长在看一些database paper的时候看到steal和no-force的字样,深入了解了一下,发现我们平时关注的redo log个undo log都是有渊源的,什么时候需要redo log,什么时候需要undo log,什么时候...

黑客画家 ⋅ 51分钟前 ⋅ 0

Mahout的推荐系统

Mahout的推荐系统 什么是推荐系统 为什使用推荐系统 推荐系统中的算法 什么是推荐系统 为什么使用推荐系统?   促进厂商商品销售,帮助用户找到想要的商品   推荐系统无处不在,体现在生...

xiaomin0322 ⋅ 52分钟前 ⋅ 0

docker里没有安装基础软件包,比如Vim,netstat, ps

一,安装VIM apt-get update 二,安装netstat命令 说明没有安装netstat工具,而该工具在 net-tools 工具包内 apt-get install net-tools 在这个时候,主要是因为apt还在运行,不能同时开两个...

aust_niuroutan ⋅ 58分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部