我相信如果你写过前后端分离的web应用程序,或者写过一些ajax请求调用,你可能会遇到过CORS错误。

  • CORS是什么?
  • 它与安全性有关吗?
  • 为什么要有CORS?它解决了什么目的?
  • CORS是怎样运行的?

如果您有这些问题,那么这篇文章非常适合您。

一、什么是CORS?

要了解什么是CORS(Cross-Origin Resource Sharing:跨站资源共享),首先我们需要了解什么是同源策略Same Origin Policy(SOP)。SOP是所有的现代浏览器都具备的安全措施,它不允许从一个加载的js脚本和资源的Origin域与另一个Origin域进行交互。换句话说,如果您的网站是www.example.com,则您无法向www.test.com发出XHR请求。

那么SOP有什么用?如果没有同源策略的限制,你想想会发生什么? 比如:您已经登录到微博,并且不小心打开了一个恶意网站。该网站可以向微博发出请求,并从您微博登录的会话中提取个人信息。这显然是巨大的安全问题,为了防止这种情况,在浏览器中实施同源策略的限制。实际上,服务器并没有意识到在浏览器端发生的这一切,您仍然可以使用curl或postman发出相同的请求,并且一切响应正常,因为这些工具上没有SOP。

如果说SOP是限制跨源访问的一种方式,那么CORS是一种绕过SOP限制并允许您的前端向服务器提出合法请求的方法。 如果您的服务端的确是存在跨域的情况(实际上对于现代分布式应用,这很常见),由于SOP限制您的客户端将无法向多节点跨域服务器发出xhr请求。救星就出现了,CORS使我们能够以安全且可管理的方式做到跨域请求,突破同源策略的限制。

二、同源策略的源(Same Origin Policy的Origin)

源由三部分组成:协议,hostip(域)和端口。例如

  • http://example.com/xxx/index.htmlhttp://example.com/yyy/index.html是同源,
  • http://example.com:80http://example.com(对于http默认端口为80)是同源。
  • 由于协议不同,http://example.com/app1https://example.com/app2是不同的源。
  • http://example.comhttp://www.example.com由于域名不同,也是不同的源
  • 非常要注意的是http://localhosthttp://127.0.0.1是不同的源

同源策略就是:不允许不同的ip、端口、协议的应用在浏览器内进行互相资源共享、请求调用。

三、CORS如何运作?

CORS规范允许服务器向浏览器返回一些HTTP Headers,浏览器可以基于这些HTTP Headers来决定是否突破SOP的限制。最主要的一个HTTP Headers是Access-Control-Allow-Origin。

//目标服务允许所有的网站对其进行跨域访问
Access-Control-Allow-Origin: *
//目标服务允许特定的网站对其进行跨域访问
Access-Control-Allow-Origin: https://example.com

CORS有两种类型的请求:“simple”简单请求和“preflight”预检请求,根据请求方法的不同由浏览器确定使用哪种请求。

simple简单请求:

如果符合以下所有条件,则API请求被视为简单请求:

  • API方法是以下方法之一:GET,POST或HEAD。
  • Content-Type请求头包含:application/x-www-form-urlencodedmultipart/form-datatext/plain

这两个条件将构成大多数简单请求的用例,但是可以在此处找到更详细的简单请求条件列表。

如果您的API请求被视为simple简单请求,这个请求就可以直接被发送给服务器。服务器使用CORS HTTP Headers进行响应,浏览器将检查Access-Control-Allow-Origin后决定这个请求是否可以突破同源策略的限制,进行下一步的处理。

preflight预检请求:

如果您的API请求不满足成为简单请求的标准(最常见不满足简单请求标准的Content-Type值为application/json),则浏览器将在发送实际请求之前发出预检请求。

举一个例子,我们尝试使用GET请求https://example.com/statusContent-Typeapplication/json,所以浏览器认为它不符合一个简单请求的标准,因此浏览器会在发出实际请求之前发出预检请求,这个预检请求是使用HTTP的 OPTIONS方法发出的:

curl --location --request OPTIONS 'http://example.com/status' \
--header 'Access-Control-Request-Method: GET' \
--header 'Access-Control-Request-Headers: Content-Type, Accept' \
--header 'Origin: http://test.com'

上面的curl就是模拟预检请求,实际作用是:浏览器希望告诉服务器,我的实际请求将使用HTTP GETmethod进行调用,Content-TypeAccept作为HTTP headers,这个请求是从https://test.com发起的。服务器响应此请求:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, HEAD, POST
Access-Control-Allow-Headers: Content-Type, Accept
  • Access-Control-Allow-Origin:允许发出请求的源,或者*可以从任何来源发出请求。(即允许跨域的源)
  • Access-Control-Allow-Methods:允许的以逗号分隔的HTTP方法列表。(即允许跨域的HTTP方法)
  • Access-Control-Allow-Headers:允许发送的HTTP headers列表。

浏览器收到服务端的预检请求响应之后,在我们的示例中服务器响应*可以从任何来源发出请求,因此现在浏览器将再次访问https://example.com/status,使用GET方法(不再是OPTIONS方法),浏览器将不再限制该请求的发出与响应数据的接收。

如果预检请求响应的Origin是特定的Access-Control-Allow-Origin: http://domain.com,浏览器将出现Cross-Origin Request Blocked错误。因为服务器端预检结果只允许http://domain.com发出跨域请求,不允许其他应用向我发出跨域请求。

四、如何处理CORS错误

我们现在知道什么是CORS及其工作原理,后面的事情其实就简单了。从上面的内容我们需要注意的是,对CORS的完全控制权在服务器,即服务器可以允许或禁止源的跨域访问。所以说跨域问题的处理一般都在服务端进行,不同的服务端的处理HTTP 请求头的代码是不一样的,当然也可以不用写代码,比如:nginx、haproxy设置。但是万变不离其宗:最终都是对HTTP Headers进行重写

我就简单的举几个例子:

比如Servlet处理跨域

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*"); //解决跨域访问报错
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
chain.doFilter(req, resp);
}

比如Spring MVC配置

@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
.allowedOrigins("*") //开放哪些ip、端口、域名的访问权限
.allowCredentials(true) //是否允许发送Cookie信息
.allowedMethods("GET","POST", "PUT", "DELETE") //开放哪些Http方法,允许跨域访问
.allowedHeaders("*") //允许HTTP请求中的携带哪些Header信息
.exposedHeaders("*"); //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
}
};
}
}

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

跨站资源共享CORS原理深度解析的更多相关文章

  1. CORS(跨站资源共享)介绍

    起因 有同学在nginx站点配置中加了一行Access-Control-Allow-Origin *,导致微信中业务数据异常,抓包看http头有两个Access-Control-Allow-Origi ...

  2. SpringSecurity环境下配置CORS跨站资源共享规则

    一.CORS简述 要说明CORS(Cross Origin Resourse-Sharing) 跨站资源共享,就必须先说同源策略.长话短说,同源策略就是向服务端发起请求的时候,以下三项必须与当前浏览器 ...

  3. 跨域资源共享CORS与JSONP

    同源策略限制: 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果没有同源策略,攻击者可以通过JavaScript获取你的邮件以及其他敏感信息,比如说 ...

  4. 跨域解决方案 - 跨域资源共享cors

    目录 1. cors 介绍 2. 原理 3. cors 解决跨域 4. 自定义HTTP 头部字段解决跨域 5. 代码演示 5. 参考链接 1. cors 介绍 cors 说的是一个机制,其实相当于一个 ...

  5. VUE SpringCloud 跨域资源共享 CORS 详解

    VUE  SpringCloud 跨域资源共享 CORS 详解 作者:  张艳涛 日期: 2020年7月28日 本篇文章主要参考:阮一峰的网络日志 » 首页 » 档案 --跨域资源共享 CORS 详解 ...

  6. 网络编程-跨域资源共享 CORS

    目录 1.什么是同源策略? 2.跨域资源共享 CORS 3.预检请求 4.CORS相关字段 5.Golang实现跨域 6.参考资料 1.什么是同源策略? 如果两个 URL 的 protocol.por ...

  7. 跨域资源共享(CORS)问题解决方案

    CORS:Cross-Origin Resource Sharing(跨域资源共享) CORS被浏览器支持的版本情况如下:Chrome 3+.IE 8+.Firefox 3.5+.Opera 12+. ...

  8. java8Stream原理深度解析

    Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...

  9. mysql索引原理深度解析

    mysql索引原理深度解析 一.总结 一句话总结: mysql索引是b+树,因为b+树在范围查找.节点查找等方面优化 hash索引,完全平衡二叉树,b树等 1.数据库中最常见的慢查询优化方式是什么? ...

随机推荐

  1. 【5】JMicro免费在线消息服务

    JMicro是一个用Java语言实现的开源微服务全家桶, 源码地址:https://github.com/mynewworldyyl/jmicro, Demo地址:http://jmicro.cn/. ...

  2. springboot中关于Long类型返回前端精度丢失问题处理

    使用了HuTool这个雪花算法后,会出现丢失精度的问题 hutool算法使用地址 对于一些大的业务表,自增主键这里 接口层得注意下是否会产生大数值 设计接口的时候采用String类型. 在项目中,我们 ...

  3. Linux系统编程 —互斥量mutex

    互斥量mutex 前文提到,系统中如果存在资源共享,线程间存在竞争,并且没有合理的同步机制的话,会出现数据混乱的现象.为了实现同步机制,Linux中提供了多种方式,其中一种方式为互斥锁mutex(也称 ...

  4. springboot+mybatis集成分页功能

    1.使用idea搭建srpingboot项目 在pom.xml文件中引入如下的依赖: <dependency> <groupId>org.springframework.boo ...

  5. Java泛型中的类型参数和通配符类型

    类型参数 泛型有三种实现方式,分别是泛型接口.泛型类.泛型方法,下面通过泛型方法来介绍什么是类型参数. 泛型方法声明方式:访问修饰符 <T,K,S...> 返回类型 方法名(方法参数){方 ...

  6. 《C++primerplus》第6章练习题

    本来前面五题都做完了,写博客时没保存好草稿= =,写了个整合版的程序,实现前五题的关键部分. 1.定义一个叫jojo的结构,存储姓名.替身和力量值,使用动态结构数组初始化二乔.承太郎和乔鲁诺乔巴纳等人 ...

  7. 浅谈BSGS

    用于求解形如\(a^x≡b\mod p\)的最小非负整数解\(x\). 由欧拉定理\(a^{\phi(p)}≡1\mod p\)可以知道,我们找的解如果有解则一定在\(\phi(p)\)范围内,而最大 ...

  8. Android高级控件(下)

    计时器(Chronometer) getBase() 基准时间 setFormat() 设置显示格式 start() 开始计时 stop() 停止计时 setOnChronometerListener ...

  9. idea 2020.1 Mybatis log plugin破解插件

    下载 链接: https://pan.baidu.com/s/1FTgtJiyzxxaNxWLyX4OgZw 密码: w7w8 idea安装本地插件

  10. Codeforces Global Round 11 A~D题解

    A.Avoiding Zero 题目链接:https://codeforces.ml/contest/1427 题目大意:给定一个数组a1,a2...,an,要求找出一个a重排后的数组b1,b2,.. ...