自学内容网 自学内容网

CORS解决浏览器跨域请求(同源策略)限制原理、后端springboot CROS跨域解决方案

1 浏览器的同源策略

1.1 什么是源(origin)?

源=协议+域名+端口号

注意点 :

  • 不看后面跟着的路径,如http://localhost:8080/usr/home 的源是http://localhost:8080
  • httphttps是两种连接协议

1.2 跨域请求?

首先了解两个概念:

  • 所处源:浏览器页面显示的源
  • 目标源:请求的服务器源

所处源和目标源不一致就是非同源,就是跨域,因此若前后端跨域,那么前端发送的就是跨域请求。

1.3 同源策略(跨域限制)是什么?

同源策略是浏览器为了确保资源安全而遵循的一种策略,他会对访问的资源进行限制。也就是说,这一策略是浏览器执行的。
需要注意的是:

  • 跨域限制仅仅存在浏览器端,服务端不存在跨域限制(两个源不同的服务器之间理论上可以互相请求并接收数据)
  • 浏览器对标签跨域没有限制,比如<src>、<script>、<img>里面有一些跨域请求是可以正常响应的

1.3.1 同源策略的具体限制?

  • Dom限制:源A的脚本无法读取源B的Dom(内嵌iframe可以显示,但是无法通过js代码获取Dom元素)
  • Cookie限制:源A无法访问源B的cookie(用户信息安全)
  • Ajax响应数据限制:源A可以给源B发送请求,源B也可以正常响应并返回数据,但是响应结果会被浏览器拦截(实际开发最常碰见的问题)

那么,浏览器是如何进行拦截的呢?

1.3.2 浏览器CORS校验

下图是前后端响应时序图,js代码运行在浏览器上,通过浏览器向后端服务器发送ajax请求,服务器正常响应并返回数据,但此时浏览器会做一次校验,校验通过才能正常显示数据,否则会对数据进行拦截并抛出异常。
这个校验的过程就是同源策略执行的时间点,浏览器会根据CORS(Cross-Origin Resource Sharing)规范进行校验,若浏览器和服务器处于同一源则检验通过,否则不通过。
在这里插入图片描述

2 CORS解决Ajax跨域问题

2.1 CORS概述

CORS(Cross-Origin Resource Sharing,跨域资源共享)是用于控制浏览器校验跨域请求的一套规范,若要解决跨域限制,服务器需要依照CORS规范,添加特定响应头来控制浏览器校验,大致规则如下:

  • 服务器明确表示拒绝跨域请求或没有表示的,则校验不通过
  • 服务器表示允许跨域请求,则浏览器校验通过

由于要求服务器在响应体添加相关字段来通过校验,所以服务器必须是自己人,比如无法向百度的接口发送跨域请求,因为人家不认识你,就无法在响应体头里配置源。

2.2 CORS解决简单请求跨域

2.2.1 简单请求

简单请求,需要同时满足以下三个条件:

  1. 请求方法为GET、HEAD、POST
  2. 请求头字段符合《CORS安全规范》(只要不修改请求头,如添加字段,基本都符合)
  3. 请求头的content-type必须是‘text/plain’‘multipart/form-data’‘application/x-www-form-urlencoded’

2.2.2 简单请求CORS解决方案

浏览器在发送请求的时候,请求头里会携带‘origin’字段标明请求的源,所以服务器若允许跨域请求,只要在响应头(Header)的‘Access-Control-Allow-Origin’字段添加可以跨域访问的源即可。
如:

//request header:
`……
Origin:http://127.0.0.1:1234
……`
//Response header:
`……
Access-Control-Allow-Origin:http://127.0.0.1:1234
……`

注意:

  • 响应体里的访问允许源要完全和请求源一致,不能在末尾多一个斜杠
  • localhost和127.0.0.1要区分开,origin和acao保持一致

2.3 CORS解决复杂请求跨域

2.3.1 复杂请求

只要不满足简单请求的任一条件,就是复杂请求。

2.3.2 预检请求

进行复杂请求前会先发送一个预检请求(浏览器自动发起),用来向服务器确认是否允许接下来的【一系列】跨域请求。预检请求是一个options请求,只有通过了预检请求才会继续发起实际的跨域请求。
预检请求头一般包括:

字段解释
Origin请求源
Access-Control-Request-Method实际请求(复杂请求本身,非预检请求)的HTTP方法
Access-Control-Request-Headers实际请求中使用的自定义头(自定义的头字段)

2.3.3 复杂请求CORS解决方案

Step 1: 服务器首先需要通过浏览器的预检请求,那么需要在响应头里返回如下字段:

字段解释
Access-Control-Allow-Origin允许的源
Access-Control-Allow-Methods允许的方法
Access-Control-Allow-Headers允许的自定义头
Access-Control-Max-Age预检请求的结果缓存时间(可选,设定该字段后,在设定时间内满足访问条件的复杂请求将不再重复发送预检请求,而是直接进行复杂请求)

Step 2: 处理实际跨域请求,这一步同简单请求,在响应头‘Access-Control-Allow-Origin’字段添加源

3 Springboot CROS跨域解决方案

介绍了允许跨域请求的原理后,就可以根据相关字段在后端进行配置,以通过同源策略。

3.1 配置全局跨域访问

3.1.1 继承WebConfigConfigurer

新建跨域config类,继承WebConfigConfigurer,重写addCorsMappings方法:

@Configuration
public class WebMvcConfig  implements WebMvcConfigurer {
    @Override
public void addCorsMappings(CorsRegistry registry) {      
//添加映射路径,哪些请求的url路径可以进行处理,一般会将url和controller进行绑定,"/**"则表示所有路径都进行处理
        registry.addMapping("/**")                 
//表示允许所有的域都可以请求
                .allowedOrigins("*")
                //表示在3600秒内不需要再发送预校验请求
                .maxAge(3600)
                //是否发送Cookie信息
                .allowCredentials(true)
                //表示允许跨域请求的方法
                .allowedMethods("GET","POST", "PUT", "DELETE")
                //表示允许跨域请求包含content-type
                .allowedHeaders("*")
                //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息,如果需要获取则在exposedHeaders里定义好需要暴露的字段)
                .exposedHeaders("Header1", "Header2");
    }
}

3.1.2 配置cors过滤器,新建自己的bean覆盖原来的

@Configuration
public class CorsFilterConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
          config.addAllowedOrigin("*");
          config.setAllowCredentials(true);
          config.addAllowedMethod("*");
          config.addAllowedHeader("*");
          config.addExposedHeader("*");
 
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configSource);
    }
}

3.2 配置局部跨域访问

3.2.1 @CrossOrigin注解(和controller配合使用)

注解常用属性(若不加属性则表示没有限制):

字段解释
origins指定允许访问的源
allowedHeaders指定允许的请求头
allowedMethods指定允许的HTTP方法
exposedHeaders指定允许暴露的响应头
allowCredentials指定是否允许发送身份验证信息(如cookie)
maxAge指定预检请求(OPTIONS)的缓存时间,单位为秒

用在类上
则该类所有方法都可以被允许的域访问:

@Controller
@CrossOrigin("http://localhost:1234")
public class EmpController {
    @RequestMapping("/test")
    public String getTestInfo() {
        return “testinfo”;
}
@RequestMapping("/test2")
    public String getTestInfo2() {
        return “testinfo2”;
    }
}

用在方法上
没有配置@CrossOrigin的方法无法进行跨域访问:

@Controller
public class EmpController {
//可以跨域访问
@CrossOrigin("http://localhost:1234")
@RequestMapping("/test")
    public String getTestInfo() {
        return “testinfo”;
}
//不可以跨域访问
@RequestMapping("/test2")
    public String getTestInfo2() {
        return “testinfo2”;
    }
}

3.2.2 HttpServletResponse中设置header

每个都要设置,太麻烦。

@RequestMapping("/test")
@ResponseBody
public String test(HttpServletResponse response){
response.addHeader("Access-Control-Allow-Origin", "*");
    return "test";
}

原文地址:https://blog.csdn.net/weixin_43281875/article/details/142390652

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!