我相信如果你写过前后端分离的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. python文档翻译之使用python解释器

    Python解释器通常安装在/usr/local/bin/python3.6,把/usr/local/bin目录设置到UNIX shell的搜索路径就可以使用下面的命令运行python: python ...

  2. golang slice学习

    关于获取slice相关内存地址操作 s := make([]int, 1) t.Log(unsafe.Pointer(&s))// 获取当前slice 结构体实例的内存地址 t.Log(uns ...

  3. 7.kafka HA

  4. Servlet中关于中文乱码

    一.客户端请求服务器的数据有乱码 1.get方式请求 ①修改tomcat/conf/server.xml,在<Connector> 标签中添加属性useBodyEncodingForURI ...

  5. svn提交代码出错

    今天提交代码的时候一直报错,下面是错误信息 Error: Commit failed (details follow):  Error: Commit blocked by pre-commit ho ...

  6. java中的几种基础排序

    import java.util.Random;import java.util.Arrays; public class Puppy {     public static void main(St ...

  7. HTML中限制input 输入框输入内容

    限制 input 输入框只能输入纯数字1.onkeyup = "value=value.replace(/[^\d]/g,'')" 使用 onkeyup 事件,有 bug ,那就是 ...

  8. java版集成Allure报告--注释使用说明

    testNG集成Allure报告--注释使用说明 前置条件 首先需要下载allure的zip包解压,然后配置环境变量即可(win).allure的GitHub下载地址: 然后执行testn.xml或者 ...

  9. 图文并茂C++精华总结 复习和进阶

    字面常量不可以有引用,因为这也不需要使用符号来引用了,但是字面常量却可以初始化const引用,这将生成一个只读变量: 对变量的const修饰的引用是只读属性的: 也就是说,const修饰的引用,不管是 ...

  10. CF538B Quasi Binary 思维题

    题目描述 给出一个数 \(n\),你需要将 \(n\) 写成若干个数的和,其中每个数的十进制表示中仅包含\(0\)和\(1\). 问最少需要多少个数 输入输出格式 输入格式: 一行 一个数 \(n(1 ...