HTTP访问控制(CORS)- 学习笔记

本人博客文章地址:点击进入

今天在写一个简单的 mock-server 的时候遇到了跨域问题,导致前端页面不能正常与 mock-server 进行数据交互,之后我查询了相关资料,了解了一下 CORS 的相关知识。

一. 简介

当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。

而CORS 允许浏览器向跨源服务器,发出跨域请求,从而克服了AJAX只能同源使用的限制。

CORS是一个W3C标准,它同时需要浏览器和服务端的支持,其中浏览器端的支持如下

image.png

浏览器基本都支持,因此,想要实现CORS通信,只要服务器实现了CORS接口即可。

二. 简单请求与非简单请求

cors请求根据发出的请求是否满足一些条件,将请求分为两种:简单请求与非简单请求。

1. 简单请求

1.1 基本

若请求满足所有下述条件,则该请求可视为“简单请求”:

  • 请求方法为 Head、Get、Post 中的一个
  • 请求头信息中仅包含 对 CORS 安全的首部字段集合 :Accept、Accept-Language、Content-Language、Content-Type,且 Content-Type 仅限于application/x-www-form-urlencoded、multipart/form-data、 text/plain 中的一个。

对于简单请求,浏览器直接发出一个CORS请求,并在请求头中加入一个 Origin 段来描述本次请求来自哪个源(协议 + 域名 + 端口)。如下就是一个简单请求的请求头:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example

而服务器则需要在返回头中包含 Access-Control-Allow-Origin 段,来表明哪些外域可以访问。如下是一个返回头

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

其中 Access-Control-Allow-Origin:* 表明该资源可以被任意外域访问。如果服务端仅允许来自 http://foo.example 的访问,该首部字段的内容如下:Access-Control-Allow-Origin: http://foo.example。现在,除了 http://foo.example,其它外域均不能访问该资源。

1.2 withCredentials

CORS请求默认不发送Cookie和HTTP认证信息,如果要发送Cookie,首先需要在 AJAX 请求中打开 withCredentials 属性,且服务器的返回头中必须包含 Access-Control-Allow-Credentials:true 。需要注意的是,当请求中包含cookie时,即打开了 withCredentials 后,服务器返回头中 Access-Control-Allow-Origin 就不能再设置为 *,而必须要显示指明允许哪些源访问。

2. 非简单请求

2.1 基本

非简单请求是指那些包含特殊要求的请求,对于这一类请求,浏览器会在正式请求之前发出一个OPTION请求来询问服务器是否支持该次请求,这个OPTION请求被称为‘预检请求’。在服务端回应允许后,浏览器才会发出真正的非简单请求。

2.2 预检请求

如下是一个 预检请求 的请求头:

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
除了Origin 字段,还包含了Access-Control-Request-Method 和 Access-Control-Request-Headers 字段,分别表明 CORS 请求会用到的 请求方法 和 额外的请求头字段。

服务端在收到预检请求后会做出回应,如下是预检请求的返回头:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
Access-Control-Allow-Methods 表示服务端允许的请求方法,Access-Control-Allow-Headers 表示服务端允许的请求头额外字段,Access-Control-Max-Age 指定本次预检请求的有效期,有效期内不用发出另一条预检请求。

2.2 实际请求

预检请求完成后,浏览器会将实际请求发出,和简单请求一致。

三. 相关请求、响应头字段

1. 请求

Origin:预检请求或实际请求的源站。协议 + 域名 + 端口。不管是否为跨域请求,ORIGIN 字段总是会被发送。

Access-Control-Request-Method:预检请求专用。将实际请求所使用的 HTTP 方法告诉服务器。

Access-Control-Request-Headers:预检请求专用。将实际请求所携带的额外头字段告诉服务器。

2. 响应

Access-Control-Allow-Origin:指定允许访问该资源的外域 URI。当请求打开 withCredentials 属性时,不可返回 ‘*’。

Access-Control-Expose-Headers:允许浏览器通过 getResponseHeader 访问的额外字段。

Access-Control-Max-Age:预检请求缓存时间。

Access-Control-Allow-Credentials:当请求打开 withCredentials 属性时,需要返回true。

Access-Control-Allow-Methods:预检请求专用。指明实际请求所允许使用的 HTTP 方法。

Access-Control-Allow-Headers:预检请求专用。指明实际请求所允许携带的额外头字段。

四. 常见跨域错误

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'XXX' is therefore not allowed access.

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'XXXX' is therefore not allowed access.

以上两种错误都是由于服务端返回头没包含Access-Control-Allow-Origin字段导致的,解决办法是添加上该字段并让请求源包含在字段中。


Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains the invalid value 'XXX'. Origin 'XXX' is therefore not allowed access.

The 'Access-Control-Allow-Origin' header contains the invalid value 'XXX'. Origin 'XXX' is therefore not allowed access.

以上两种错误都是由于服务端返回头中的Access-Control-Allow-Origin字段不包含请求源,解决办法是修改该字段使请求源包含在字段中。


Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'XXX' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'XXX' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

以上两种错误都是由于请求打开 withCredentials 属性,但服务端将Access-Control-Allow-Origin设置为了‘’,解决办法是用精确写法替换‘’。


Request header field XXX is not allowed by Access-Control-Allow-Headers in preflight response.

这种错误是由于请求头中包含Access-Control-Request-Headers,但服务器未返回对应的Access-Control-Allow-Headers

作者博客地址:https://liuhuihao.com
作者gitHub:https://github.com/geminate

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • 引用自HTTP访问控制(CORS) 当 Web 资源请求由其它域名或端口提供的资源时,会发起跨域 HTTP 请求(...
    有涯逐无涯阅读 2,527评论 0 4
  • CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 ...
    奇特思维家阅读 1,100评论 0 3
  • 什么是跨域HTTP请求 现代浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵...
    孤独的人最善良阅读 1,147评论 0 0
  • CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 ...
    myccy8阅读 411评论 0 2
  • 最近工作比较忙,连续加班,今天总算不用加班了,回来一鼓气看了好几集于正的宫廷戏,电视里的宫女能干又魄力,早晚会逆袭...
    吴宁_16ee阅读 152评论 0 0