CORS(跨域资源共享)

CORS(跨域资源共享)使用额外的HTTP头部告诉浏览器,允许运行在origin(domain)上的Web应用访问来自不同源服务器上的指定资源。

浏览器访问一个web应用,这个web应用会发很多的跨域请求,例如加载不同源的JS/CSS脚本,或者加载不同源图片等。但是并没有发现请求的异常,这些资源是可以正常返回的。而通过JS发送的跨域HTTP请求却时常得到错误,所以跨域请求很常见,但是浏览器对于请求跨域的限制却只存在于脚本发送的HTTP请求(Ajax/Fetch)。

同源限制在安全上是有其必要性的,例如可以很轻松规避CSRF攻击。

通过上面的描述可以看出来同源策略的限制存在于浏览器端,而CORS策略用额外的HTTP请求头字段来告诉浏览器,该资源是允许被当前域上的web应用跨域访问的。

CORS的具体步骤

那么具体CORS是怎么做的呢?

  1. 浏览器察觉请求跨域没有发起请求?
  2. 浏览器发起跨域请求没有正常返回结果?

上面说到“通过额外的HTTP头告诉浏览器源上的web应用被允许访问来自不同源服务器上的指定资源”。告诉浏览器的自然是通过服务端的响应携带的额外的HTTP头,所以可以看出来请求是发送了的。那么服务端是携带了标识当前源允许访问的该资源的HTTP头?如果允许的话自然是请求一切正常,不允许的话浏览器则会报错并且不会将请求结果返回给请求的发起方,也就是Ajax/Fetch代码,并且代码中获取不到是哪一步出了错只能在浏览器中看到错误日志(为了安全)。

那么就只是这样吗?跨域请求失败是因为浏览器正常发送了请求,服务端正常响应了请求,然后浏览器发觉响应头中没有允许跨域的标识,然后拦截返回结果并报错。

并不完全是这样,这只是CORS的一部分,这部分被称为简单请求。

既然有简单请求就有非简单请求。非简单请求的具体步骤和上面描述的简单请求很不一样,会在发送真正的请求之前发送一个预检请求(preflight request)询问服务端是否允许当前源跨域访问该资源,允许则继续发送真正的请求,否则直接报错。

所以上面的两种做法都被应用到CORS策略中:一种是拦截请求的返回结果,一种是不发送真正的跨域请求。

简单请求

简单请求并不会发送预检请求,而是直接发送真正的请求。简单请求必须要全部满足下面的条件:

  • 使用下列方法之一:
    • GET
    • HEAD
    • POST
  • 不得人为设置该集合之外的其他首部字段。该集合为:
    • Accep
    • Accept-Language
    • Content-Language
    • Content-Type(需要注意额外的限制)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • Content-Type 的值仅限于下列三者之一:(这个集合中没有application/json
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded
  • 请求中的任意XMLHttpRequestUpload`对象均没有注册任何事件监听器;XMLHttpRequestUpload对象可以使用 XMLHttpRequest.upload 属性访问。
  • 请求中没有使用ReadableStream对象。

下面我们将从源http://dev.jd.com:9091访问http://dev.jd.com:9090的资源。

如果没有使用CORS显然会被浏览器的同源策略限制从而报错,如下:

在这里插入图片描述

分别查看请求头:

GET /corsget HTTP/1.1
Host: dev.jd.com:9090
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
Accept: */*
Origin: http://dev.jd.com:9091
Referer: http://dev.jd.com:9091/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

通过请求头可以看出来其中包含了很多简单请求定义的字段以外的字段,但是却并没有触发预检请求,这是因为这些头字段并不是人为设置的

响应头:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 16
ETag: W/"10-oV4hJxRVSENxc/wX8+mA4/Pe4tA"
Date: Mon, 06 Apr 2020 09:45:36 GMT
Connection: keep-alive

修改服务端程序,让响应头带上标识,告诉浏览器允许源http://dev.jd.com:9091上的web应用访问不同源(http://dev.jd.com:9090)上的资源/corsget。

请求头同上,响应头如下:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 16
ETag: W/"10-oV4hJxRVSENxc/wX8+mA4/Pe4tA"
Date: Mon, 06 Apr 2020 09:58:06 GMT
Connection: keep-alive

可以看到多了一个Access-Control-Allow-Origin这个字段,该字段表示被允许访问该资源的不同源,这里指定了*表示告诉浏览器任何源都可以访问该资源。

通过观察还可以发现请求头中有字段Origin正好对应的是就是http://dev.jd.com:9091web应用所在的源。

在这里插入图片描述

非简单请求

上面简单请求的条件只要有一个没有满足就会变成非简单请求。非简单请求会首先发送一个预检请求询问服务端是否允许跨域,服务端允许后才会发送真正的请求。

注:chrome的network面板中看不到预检请求,可以查看 chrome://flags/#out-of-blink-cors 配置,改成 disabled 后重启 Chrome ,或者换个浏览器Firefox是可以看到的,目前是74.0版本。

预检的请求头:

OPTIONS /corsget HTTP/1.1
Host: dev.jd.com:9090
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: GET
Access-Control-Request-Headers: content-type
Origin: http://dev.jd.com:9091
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
Accept: */*
Referer: http://dev.jd.com:9091/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

通过人为修改请求头的content-type为application/json将原本的简单请求变成了非简单请求,因为application/json并不在简单请求的三种content-type中。

这样就需要首先发送一个预检请求。

可以看到请求头中有如下字段:

  1. Access-Control-Request-Method: GET

    用于预检请求,将实际发送的请求的method告知服务器

  2. Access-Control-Request-Headers: content-type

    用于预检请求,将实际发送的请求头(不满足简单请求条件)告知给服务器

  3. Origin: http://dev.jd.com:9091

    告诉服务器请求源

预检响应头:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS
Access-Control-Allow-Headers: Content-Type
Content-Type: text/html; charset=utf-8
Content-Length: 0
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Date: Mon, 06 Apr 2020 10:57:40 GMT
Connection: keep-alive

可以看到如下字段:

  1. Access-Control-Allow-Origin: *

    告诉浏览器任何源都可访问该资源

  2. Access-Control-Allow-Methods: OPTIONS
    告诉浏览器options被允许跨域访问该资源。options并不在简单请求被允许的method中,但是预检请求确是options,所以需要指定options被允许。

  3. Access-Control-Allow-Headers: Content-Type

    告诉浏览器三个Content-Type值之外的Content-Type值被允许跨域访问该资源。因为application/json并不在简单请求的三个content-type中。

然后发送实际的get请求,请求头如下:

GET /corsget HTTP/1.1
Host: dev.jd.com:9090
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Origin: http://dev.jd.com:9091
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1
Content-Type: application/json
Accept: */*
Referer: http://dev.jd.com:9091/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

实际请求的响应头如下:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 16
ETag: W/"10-oV4hJxRVSENxc/wX8+mA4/Pe4tA"
Date: Mon, 06 Apr 2020 10:57:40 GMT
Connection: keep-alive

可以看到实际请求的响应头中并没有复杂的访问控制类型的HTTP头,只有一个Access-Control-Allow-Origin: *。在实际请求的响应头中这个字段是必须的,如果没有这个头部即使预检通过了,实际发送的请求还是会失败,返回的结果还是会被浏览器拦截,并不会返回给脚本,并报错。

在这里插入图片描述

跨域请求和凭证

Ajax和Fetch的跨域请求默认不会携带凭证。可以通过Ajax/Fetch的设置让发送请求的时候带上凭证,但是如果服务端并不允许携带凭证的跨域请求,那么理所当然的跨域请求会失败。

在这里插入图片描述
Ajax: xhr.withCredentials = true

Fetch: fetch(url, {credentials: 'include', mode: 'cors'})

当服务端设置 Access-Control-Allow-Credentials: true 允许跨域请求携带凭证的时候对于Access-Control-Allow-Origin还有一个限制,就是值不能为*。

在这里插入图片描述
那么我们就需要在后端设置上指定允许携带凭证跨域的源,如果有多个怎么办呢?因为Access-Control-Allow-Origin这个字段并不能设置多个值,可以通过代码获取请求头的Origin来判断是否允许获取该资源,允许的话将Origin值设置给响应的HTTP头字段Access-Control-Allow-Origin即可。
在这里插入图片描述
仔细观察就可以发现Access-Control-Allow-Credentials: true这个响应头在预检和实际请求的响应头中被返回了两次(一次都不能少,否则会报错,一样是跨域错误),但是之前设置的Access-Control-Allow-Headers: Content-Type只有在预检的时候才会被返回。

其实关于Access-Control的HTTP头还有一个是控制预检请求的缓存时间的,就是Access-Control-Max-Age单位是秒。

所以初步猜测Access-Control-Allow-Credentials这个响应头并不能被缓存?

问题:

脚本会发送跨域请求,Origin指向的是HTML所在源还是脚本所在源呢?

参考:

  1. HTTP访问控制(CORS)
  2. Server-Side Access Control
  3. Fetch

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转]jQuery设计思想

转自:http://kb.cnblogs.com/page/109875/ jQuery是目前使用最广泛的javascript函数库。 据统计,全世界排名前100万的网站,有46%使用jQuery,远远超过其他库。微软公司甚至把jQuery作为他们的官方库。 对于网页开发者来说&#xff…

Java转换难题者,不适合工作(或面试)

一个非常艰苦的面试问题可能是这样的: int i Integer.MAX_VALUE; i 0.0f; int j i; System.out.println(j Integer.MAX_VALUE); // true为什么打印出正确的文字? 乍一看,答案似乎很明显,直到您意识到如果长时间更改int&…

问题:jquery给标签添加事件,但标签还未加载会成功吗

之后研究解决转载于:https://www.cnblogs.com/sz-toosimple/p/11170912.html

Access-Ctrol-Allow-Headers:*兼容问题导致的跨域失败

现象: 通过抓包看到在部分客户端上跨域的非简单请求只发送一个预检的OPTIONS请求,之后的真实请求并没有发送。 出现问题的环境: 部分IOS低版本系统。 windows系统微信内必现(2020-04-29)。 分析 通过上面条件OPT…

在github上托管Maven存储库(包含源代码和javadoc)

如何通过maven将小型开源库提供给其他开发人员? 一种方法是将其部署在Maven Central Repository上 。 我想要做的是将其部署到github ,因此我可以自由地对其进行修改。 这篇文章将告诉您如何做到这一点。 我将工件部署到github的典型方法是使用mvn depl…

关于移动端页面强制竖屏

最近工作中写了一个移动端的页面,本来是没什么的,但是有一个要求感觉很奇怪,从前也没有遇到过,就是我写的这个页面需要放在一个APP中,但是这个APP是横屏的,打开这个页面的webview也是横屏的(最新…

敏捷开发绩效管理之四:为团队设立外部绩效目标(目标管理,外向型绩效)...

这是敏捷开发绩效管理的第四篇。(之一,之二,之三,之四,之五,之六,之七)最近在看德鲁克的书,发现其中很明确地写着“企业的绩效只存在于外部,而企业内部只有成…

面向对象程序设计-C++ Default constructor Copy constructor Destructor Operator Overloading【第九次上课笔记】...

先上笔记内容吧&#xff1a; 这次上课的内容有关 构造函数析构函数运算符重载return * this内容很细&#xff0c;大家好好回顾笔记再照应程序复习吧 :) #include <iostream>using namespace std;class Integer { public:int i;int geti () const {return this->i;}vo…

阅读react-redux源码 - 一

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现 阅读react-redux源码零中准备了一些react、redux和react-redux的基础知识。从使用的例子中可以看出来顶层的代码中需要用一个来自react-redux的Provider组件提供r…

【K8S in Action】服务:让客户端发现pod 并与之通信(2)

一 通过Ingress暴露服务 Ingress (名词&#xff09; 一一进入或进入的行为&#xff1b;进入的权利&#xff1b;进入的手段或地点&#xff1b;入口。一个重要的原因是每个 LoadBalancer 服务都需要自己的负载均衡器&#xff0c; 以及 独有的公有 IP 地址&#xff0c; 而 Ingres…

事件绑定on与hover事件

今天项目中UI设计了一个鼠标划入和划出的效果&#xff0c;本来这个小效果是非常简单的&#xff01;可是在实际的生产环境中就出现了一点点问题&#xff01;因为在实际的环境中&#xff0c;数据全部是用ajax异步加载进去的&#xff0c;这样就造成了hover方法不能用了。先看一下原…

Java EE + MongoDb与Apache TomEE和Jongo Starter项目

知道MongoDB和Java EE &#xff0c;但是您不知道如何将两者集成在一起&#xff1f; 您是否阅读了很多有关该主题的内容&#xff0c;但没有找到适合该目的的解决方案&#xff1f; 这个入门项目适合您&#xff1a; 您将学习如何以一种时尚的方式使用MongoDB和Java EE &#xff0…

hdu 3831

神题&#xff0c;经典dp 关键是状态的表示。 f[i][j][k] 原串后i个字符&#xff0c;与目标后j个字符做匹配&#xff0c;在这之前最近一次发生的后缀操作为“置k”&#xff0c;k52时表示不置后缀 转载于:https://www.cnblogs.com/zhaozhe/archive/2011/08/26/2154684.html

1017 A除以B (20 分)

本题要求计算 /&#xff0c;其中 A 是不超过 1000 位的正整数&#xff0c;B 是 1 位正整数。你需要输出商数 Q 和余数 R&#xff0c;使得 ABQR 成立。 输入格式&#xff1a; 输入在一行中依次给出 A 和 B&#xff0c;中间以 1 空格分隔。 输出格式&#xff1a; 在一行中依次输出…

阅读react-redux源码(二) - createConnect、match函数的实现

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现 上一节看了Provider组件的实现&#xff0c;主要做的事情就是通过Context透传了来自redux的store和监听store变化的事件对象Subscription的实例。 本节会深入到co…

一个罐子统治一切:Apache TomEE + Shrinkwrap == JavaEE引导

警告&#xff1a;我不是Spring Boot的专家。 我发现很多事情对此非常有趣&#xff0c;并且当然可以真正改善您的日常工作。 而且&#xff0c;我对Spring Boot没有任何反对&#xff0c;也没有开发或使用它的人。 但是我认为社区高估了该产品。 一年前&#xff0c;我开始收到很多…

iview-admin框架运行步骤

第一步&#xff1a; 前往github下载整个iview-admin框架的全部源码 github地址&#xff1a; https://github.com/iview/iview-admin 第二步&#xff1a; 点击Clone or download绿色按钮。下载整个压缩包 第三步&#xff1a; 解压至D盘&#xff0c;在根目录中按 1、前往github下…

阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories mapStateToPropsFactories import { wrapMapToPropsC…

Xcode 升级后,常常遇到的遇到的警告、错误,解决方法(转)

从sdk3.2.5升级到sdk 7.1中间废弃了很多的方法&#xff0c;还有一些逻辑关系更加严谨了。1&#xff0c;警告&#xff1a;“xoxoxoxo” is deprecated解决办法&#xff1a;查看xoxoxoxo的这个方法的文档&#xff0c;替换掉这个方法即可。2&#xff0c;警告&#xff1a;Declarat…

.net 垃圾回收学习[How To: Use CLR Profiler][翻译学习]【2】

http://msdn.microsoft.com/zh-cn/library/ms979205 注意&#xff1a;内容可能已经过期了。 注意&#xff1a;CLR Profiler最新版本&#xff1a;http://www.microsoft.com/download/en/details.aspx?id16273 Identifying Common Garbage Collection Issues 可以使用CLR Profil…