原文地址:https://blog.csdn.net/badmoonc/article/details/82706246
简介
CORS:全称"跨域资源共享"(Cross-origin resource sharing)。
CORS需要浏览器和服务器同时支持,才可以实现跨域请求,目前几乎所有浏览器都支持CORS,IE则不能低于IE10。CORS的整个过程都由浏览器自动完成,前端无需做任何设置,跟平时发送ajax请求并无差异。so,实现CORS的关键在于服务器,只要服务器实现CORS接口,就可以实现跨域通信。
请求类型:
CORS分为简单请求和非简单请求(需预检请求)两类
符合以下条件的,为简单请求
-
请求方式使用下列方法之一:
-
GET
-
HEAD
-
POST
-
Content-Type 的值仅限于下列三者之一:
-
text/plain
-
multipart/form-data
-
application/x-www-form-urlencoded
对于简单请求,浏览器会直接发送CORS请求,具体说来就是在header中加入origin请求头字段。同样,在响应头中,返回服务器设置的相关CORS头部字段,Access-Control-Allow-Origin字段为允许跨域请求的源。请求时浏览器在请求头的Origin中说明请求的源,服务器收到后发现允许该源跨域请求,则会成功返回,具体如下:
在这里,http://localhost:3001为我们当前发送请求的源,如果服务器发现请求在指定的源范围内,则会返回响应的请求结果, 否则会在控制台报错,如下图所示,在这里需要注意的是,尽管请求失败,但返回的状态码依然可能为200。所以在做处理时需要格外注意。
非简单请求(预检请求)
-
使用了下面任一 HTTP 方法:
-
PUT
-
DELETE
-
CONNECT
-
OPTIONS
-
TRACE
-
PATCH
-
Content-Type 的值不属于下列之一:
-
application/x-www-form-urlencoded
-
multipart/form-data
-
text/plain
当发生符合非简单请求(预检请求)的条件时,浏览器会自动先发送一个options请求,如果发现服务器支持该请求,则会将真正的请求发送到后端,反之,如果浏览器发现服务端并不支持该请求,则会在控制台抛出错误,如下:
如果非简单请求(预检请求)发送成功,则会在头部多返回以下字段
-
Access-Control-Allow-Origin: http://localhost:3001 //该字段表明可供那个源跨域
-
Access-Control-Allow-Methods: GET, POST, PUT // 该字段表明服务端支持的请求方法
-
Access-Control-Allow-Headers: X-Custom-Header // 实际请求将携带的自定义请求首部字段
下图为一个预检请求实例:
红框标注的为预检请求发送的查询,服务端支持我们的请求后,将会发送我们真正的请求,图中绿框所示。可以看到,真正的请求响应头字段多处蓝框中所圈字段。这为服务器所支持cors请求类型和允许的自定义请求首部字段,以及支持跨域的源。
实例代码
前端代码与发送普通请求没有差异,我们只需在服务端设置即可,以node为例:
-
var express = require('express');
-
var app = express();
-
var allowCrossDomain = function (req, res, next) {
-
res.header('Access-Control-Allow-Origin', 'http://localhost:3001');
-
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
-
res.header('Access-Control-Allow-Headers', 'Content-Type');
-
next();
-
}
-
app.use(allowCrossDomain);
接下来,http://localhost:3001下的GET,PUT,POST,DELETE请求,自定义首部字段为Content-Type的非简单请求则会被正常访问,当然,你也可以将Access-control-Allow-Methods和Access-Control-Allow-Headers这两个配置删掉,删掉之后,将仅支持简单请求进行跨域。
CORS字段介绍:
(1)Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
(2)Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers
字段,则Access-Control-Allow-Headers
字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。
(3)Access-Control-Allow-Credentials
该字段与简单请求时的含义相同。
(4)Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。
总结:
总的来说,使用CORS简单请求,非常容易,对于前端来说无需做任何配置,与发送普通ajax请求无异。唯一需要注意的是,需要携带cookie信息时,需要将withCredentials设置为true即可。CORS的配置,完全在后端设置,配置起来也比较容易,目前对于大部分浏览器兼容性也比较好。CORS优势也比较明显,可以实现任何类型的请求,相较于JSONP跨域只能使用get请求来说,也更加的便于我们使用。关于jsonp跨域请求的实现,可以参照作者的另外一篇文章jsonp跨域原理