浅谈跨域资源共享(CORS)

在这里插入图片描述

古之立大事者,不惟有超世之才,亦必有坚忍不拔之志——苏轼

CORS 是什么

CORS 是一个 W3C 标准,全称是 Cross-origin resource sharing 译为 跨域资源共享,新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。

跨域资源共享标准规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求,从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证。

跨域资源共享机制的工作原理主要应用于三个场景:

  1. 简单请求
  2. 预检请求
  3. 认证请求

简单请求

简单请求是什么

请求同时满足所有下述条件,则该请求可视为 简单请求:

  1. 请求方法是以下三种方法之一:

    • HEAD
    • GET
    • POST
  2. HTTP的头信息不超出以下几种字段:

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type
  3. Content-Type 的值仅限于下列三者之一

    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

值得注意的是,这些跨域请求与浏览器发出的其他跨域请求并无二致。如果服务器未返回正确的响应头部,则请求方不会收到任何数据。因此,那些不允许跨域请求的网站无需为这一新的 HTTP 访问控制特性担心。

基本步骤

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段

下面是一个例子,浏览器发现这次跨源 AJAX 请求是简单请求,就自动在头信息之中,添加一个Origin字段。

GET /resources/access-control-with-get/ HTTP/1.1
Host: aruner.net
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
Keep-Alive: 300
Connection: keep-alive
Referer: http://arunranga.com/examples/access-control/simpleXSInvocation.html
Origin: http://arunranga.com

上面的头信息中,Origin字段用来说明,本次请求来自哪个源。服务器根据这个值,决定是否同意这次请求。

下面是响应信息

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

响应中携带了响应首部字段 Access-Control-Allow-Origin , 使用 Origin字段 和 Access-Control-Allow-Origin 字段就可以完成最简单的访问控制。

这个例子中 服务端返回的 Access-Control-Allow-Originhttp://arunranga.com,表示该域的资源可以被外域访问,也已使用 *,表示可以被任意外域访问。

预检请求

预检请求是什么

当浏览器发送一个非简单请求时,就会自动发送一个检测请求,所谓的检测请求就是在正式通信之前,增加一次 HTTP 查询请求,称为预检请求

当请求满足下述任一条件时,即应首先发送预检请求:

  1. 请求方法是以下三种方法之一:
    • PUT
    • DEL
    • CONNECT
  • OPTIONS
    • TRACE
    • PATH
  1. HTTP的头信息不超出以下几种字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type
  2. Content-Type 的值仅限于下列三者之一
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

预检请求要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。

预检请求可以避免跨域请求对服务器的用户数据产生未预期的影响。

请求消息

以下是 OPTIONS 预检请求消息示例:

OPTIONS /resources/access-control-with-post-preflight/ HTTP/1.1
Host: aruner.net
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-pingaruner
Origin: http://arunranga.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.60
Sec-Fetch-Mode: cors
Referer: http://arunranga.com/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
  • Access-Control-Request-Method:表示该请求使用的是 POST方法
  • Access-Control-Request-Headers:表示该请求携带 x-pingaruner 首部字段
  • Origin:请求来自哪个源

响应消息

以下是 OPTIONS 预检响应消息示例:

HTTP/1.1 200 OK
Date: Sat, 19 Dec 2020 15:20:30 GMT
Server: Apache
Access-Control-Allow-Origin: http://arunranga.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGARUNER, CONTENT-TYPE
Access-Control-Max-Age: 1728000
Upgrade: h2
Connection: Upgrade, Keep-Alive
Content-Length: 0
Cache-Control: max-age=172800
Expires: Mon, 21 Dec 2020 15:20:30 GMT
Vary: User-Agent
Keep-Alive: timeout=2, max=100
Content-Type: text/plain;charset=UTF-8

  • Access-Control-Allow-Methods: 表示允许使用 POST, GET, OPTIONS 请求方法
  • Access-Control-Allow-Headers: 表示允许请求携带首部字段 X-PINGARUNER
  • Access-Control-Max-Age: 表示设置响应有效时间为 1728000 秒

认证请求

CORS 的一个有趣的特性是,可以基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨源 XMLHttpRequest 请求,浏览器不会发送身份凭证信息。如果要发送凭证信息,需要设置 XMLHttpRequest 的某个特殊标志位。

如下代码所示

XMLHttpRequest.withCredentials = true;

XMLHttpRequestwithCredentials 标志设置为 true,使得向服务器发送 Cookies。如果是简单请求,所以浏览器不会对其发起 预检请求 。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。

响应消息示例

HTTP/1.1 200 OK
Date: Sat, 19 Dec 2020 15:20:46 GMT
Server: Apache
Access-Control-Allow-Origin: http://arunranga.com
Cache-Control: no-cache
Pragma: no-cache
Access-Control-Allow-Credentials: true
Set-Cookie: pageAccess=1; expires=Mon, 18-Jan-2021 15:20:46 GMT; Max-Age=2592000
Upgrade: h2
Connection: Upgrade, Keep-Alive
Cache-Control: max-age=172800
Expires: Mon, 21 Dec 2020 15:20:46 GMT
Vary: Accept-Encoding,User-Agent
Content-Length: 80
Keep-Alive: timeout=2, max=100
Content-Type: text/plain;charset=UTF-8

只有当 Access-Control-Allow-Credentials 为 true 时才会将响应信息返回给开发者。

写在最后

通过 CORS 实现跨域访问是一个比较实用的一个方案,帮助我们解决了 Ajax 只能实用同源的限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一碗周.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值