跨域资源共享(CORS, Cross-Origin Resource Sharing) 是浏览器的机制,让浏览器可以合理避开浏览器同源策略的限制,以访问不同源上的资源。
跨域请求
访问不同的域、协议或端口的资源时,浏览器会发起一个跨域请求。
以下展示了从 http://www.a.com/page.html
访问不同资源的情况
// 不同文件,不跨域
http://www.a.com/other.html
// 不同目录,不跨域
http://www.a.com/path/other.html
// 不同协议,跨域
https://www.a.com/other.html
// 不同端口,跨域
http://www.a.com:8080/other.html
// 不同域名,跨域
http://www.b.com/other.html
// 不同域名(父域名),跨域
http://a.com/other.html
// 不同域名(子域名),跨域
http://sub.a.com/other.html
// 不同域名(ip),跨域
http://119.254.98.162/other.html
预检请求(preflight request)
浏览器在发起跨域请求前会先使用 OPTIONS
方法发起一个预检请求,以获知服务器是否允许该跨域请求,服务器确认允许后才发起正式 HTTP 请求。
在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证。
简单请求
浏览器将跨域请求分为简单请求与非简单请求,简单请求不需要触发预检请求。
满足发下条件会被视为简单请求:
- 使用下列请求方法之一:
- GET
- HEAD
- POST
- 请求头信息不超出以下几种:
- Accept
- Accept-Language
- Content-Language
- Content-Type 仅限于以下三者
-
text/plain
-
multipart/form-data
-
application/x-www-form-urlencoded
-
简单请求会在请求头添加 Origin
字段,服务器根据这个值来决定是否同意这次请求。
如果同请求,服务器响应会额外添加几个字段:
- Access-Control-Allow-Origin(必须)
指定了允许访问该资源的域,其值要么是请求时
Origin
的值,要么是*
表示接受任意域名的请求; 当指定的值不是*
时,响应首部中的 Vary 字段的值必须包含 Origin; - Access-Control-Allow-Credentials(可选)
当浏览器的credentials设置为true时,是否允许浏览器读取response的内容;
返回true(唯一有效值,区分大小写)则可以,其他值均不可以。
此字段返回true时,
Access-Control-Allow-Origin
必须为请求Origin
的值,不能是*
; 此字段在预检请求的响应中时,它指定了实际的请求是否可以使用credentials; 简单请求不会被预检,当浏览器的credentials设置为true时,其响应中如果不包含该字段,浏览器将无法读取response的内容。 - Access-Control-Expose-Headers(可选):
白名单,列出了服务器允许浏览器访问的头;
默认情况下,
XMLHttpRequest.getResponseHeader()
方法只能拿到六种简单响应首部,如果想要能拿到其它字段,就需要在Access-Control-Expose-Headers
指定。 六种简单响应首部是:Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
非简单请求
非简单请求是那种对服务器有特殊要求的请求
比如请求方法是 PUT
或 DELETE
;
比如包含了限定以外的请求头,如 Authorization
或 X-Custom-Header
;
比如 Content-Type
字段值是 application/json
;
对于非简单请求,浏览器会先发起一个预检请求,得到肯定答复后,才会发起正式请求。
预检请求
预检请求使用 OPTIONS 方法,包括以下字段:
- Origin: 表明实际请求的源站;
- Access-Control-Request-Method: 表明实际请求所使用的 HTTP 方法;
- Access-Control-Request-Headers: 表明实际请求所额外携带的头部字段;
注:预检请求由浏览器自动发出,无须手动设置这些字段。
预检请求的响应
服务器收到预检请求后,检查了 Origin, Access-Control-Request-Method, Access-Control-Request-Headers
后,可以确认是否允许跨源请求,然后做出回应。
响应包括以下字段:
- Access-Control-Allow-Origin 指定了允许访问该资源的域,含义同简单请求
- Access-Control-Allow-Methods 指定了实际请求中允许使用的所有HTTP方法
- Access-Control-Allow-Headers 指定了实际请求中允许携带的所有首部字段
- Access-Control-Allow-Credentials 指定了实际的请求是否可以使用credentials,含义同简单请求
- Access-Control-Max-Age 指定了预检请求的结果能够被缓存多久,单位秒
正常跨域请求
通过预检后,正常跨域请求跟简单请求一样,浏览器会在请求头添加 Origin
字段;
服务器的回应也跟简单请求一样,必须包含 Access-Control-Allow-Origin
字段。
PHP 跨域中间件
支持php-PSR规范的跨域资源共享(cors)中间件。
安装依赖
composer require reezy/cors
配置
<?php
return [
// 是否允许所有的域
'allowed-all-origins' => env('APP_ENV') !== 'prod',
// 允许访问该资源的域
'allowed-origins' => ['http://localhost'],
// 实际请求中允许携带的所有首部字段
'allowed-headers' => ['authorization', 'content-type', 'x-requested-with'],
// 实际请求中允许使用的所有HTTP方法
'allowed-methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], // ex: GET, POST, PUT, PATCH, DELETE
// 实际的请求是否可以使用credentials
'allowed-credentials' => true,
// 白名单,列出了服务器允许浏览器访问的头
// 六种简单首部不需要指定:Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma
'exposed-headers' => [ ],
// 预检请求的结果能够被缓存多久,单位秒
'max-age' => 10 * 86400,
];
参考
HTTP访问控制(CORS)
developer.mozilla.org/zh-CN/docs/…
浏览器的同源策略
developer.mozilla.org/zh-CN/docs/…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!