跨域资源共享(CORS),是一种解决跨域问题的解决方案。它的完成需求浏览器、服务器同时支撑。又由于现代浏览器都已经支撑了这个机制,所以CORS的完成关键在于服务器。

咱们将根据“发送恳求前,是否会发送预检恳求”这一特征来将恳求分为2类,一类是简略恳求,一类是非简略恳求。

下面咱们将逐个进行解说。

简略恳求

简略恳求,直接就将恳求发送给服务器。简略恳求具有以下特征:

  • 恳求方式必须是 GETHEADPOST 这儿面的其中一个。
  • Content-Type字段的值必须是 text/plainmultipart/form-dataapplication/x-www-form-urlencoded 这儿面的其中一个。
  • 答应你新增恳求头字段,可是新增的恳求头字段 必须是下面集合里的某一个。

1、Accept
2、Accept-Language
3、Content-Language
4、Content-Type
5、Range

服务端怎么支撑?

一个事例教你运用“跨域资源共享”

特别提醒:

上方的图片便是未支撑CORS而爆出来的过错,过错信息很详细,咱们在工作中,根据过错提示一步一步修正即可。

针对简略恳求,想要让服务端支撑CORS,2种方式,分别如下:

  • Access-Control-Allow-Origin字段的值设置为 “*”。
  • Access-Control-Allow-Origin字段的值设置为“非*”。

这2种方式的差异在于恳求是否能够带着cookie。

第一种方式,想要带着用户信息,只能经过新增恳求头字段的方式来带着。
第二种方式,想要带着用户信息,除了能够运用第一种方式,还能够运用cookie。

在这篇文章里,咱们运用express来搭建服务器,express想要支撑CORS,2种手段,一类是运用第三方库,比方cors;另一类是自己完成。

咱们这儿选择自己完成。代码如下:

router.get('/req1', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.send('呼应成功-1');
});

这个时分咱们再来看一下效果:

一个事例教你运用“跨域资源共享”

什么场景下,会用到简略恳求呢?从业务上来看,跟用户没关系的功能一般都是简略恳求。一般都是GET恳求去获取一些全体资源啥的。

非简略恳求

发送真实的恳求前,会主动发送一个预检恳求,这个预检恳求是用来询问服务器,是否支撑CORS。

除了简略恳求,剩余的都是非简略恳求。

服务端怎么支撑?

想发送一个非简略恳求仍是比较简略的,首要体现在额定的恳求头字段、Content-Type的值为其他类型即可。

前端可能会这么来写:

let result = await axios.create({
    baseURL: 'http://127.0.0.1:8888/',
    headers: {
        user_token: '123-qwe-789-gpto901'
    }
})
.post(
    '/cors/req2',
    {
        name: '章三',
    }
);

后端可能会这么写:

router.post('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.send('呼应成功-1');
});

假设此刻发送恳求,那它一定会有跨域问题。

一个事例教你运用“跨域资源共享”

这个报错信息也是很全面的,怎么改正,它已经暗示咱们了:

恳求头“Access-Control-Allow-Origin”字段没有被预设在对应的恳求资源上。

最开始的时分,就有说过,非简略恳求在真实发送恳求前,会发送一个options的预检恳求。

所以咱们需求独自给这个接口加上options方法的处理,处理如下:

router.post('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.send('呼应成功-1');
});
router.options('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.send('');
});

此刻再发送以下恳求,接口仍是报错,报错信息如下:

一个事例教你运用“跨域资源共享”

那就再接着修正呗,这次提示咱们说要在“Access-Control-Allow-Headers”里增加“content-type”字段,后端接口修正如下:

router.post('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "content-type");
    res.send('呼应成功-1');
});
router.options('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "content-type");
    res.send('');
});

此刻再次点击按钮,发现仍是报错,信息如下:

一个事例教你运用“跨域资源共享”

说咱们呼应头字段里还少东西,那就接着增加呗:

router.post('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "user_token,content-type");
    res.send('呼应成功-1');
});
router.options('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "user_token,content-type");
    res.send('');
});

此刻再次点击按钮,这时咱们发现,这个非简略恳求的CORS终于成功了。

一个事例教你运用“跨域资源共享”

总结如下:

想要让服务器支撑非简略恳求的CORS,需求做出如下设置:

  • options的恳求、真实的恳求都需求设置 “Access-Control-Allow-Origin”呼应头字段。
  • options的恳求、真实的恳求都需求设置 “Access-Control-Allow-Headers”呼应头字段。

CORS过程中,恳求怎么带着cookie?

假设咱们有这样的一个cookie:

一个事例教你运用“跨域资源共享”

咱们想要去带着Cookie,需求做出如下修正:

  • 前端需求将 withCredentials 需求设置为true。
  • 后端需求将 “Access-Control-Allow-Origin” 设置为非*号。
  • 后端还需求将 “Access-Control-Allow-Credentials”设置为true。

现在来动手实践一下。

前端做出修正如下:

let result = await axios.create({
    baseURL: 'http://127.0.0.1:8888/',
    headers: {
        user_token: '123-qwe-789-gpto901'
    },
    withCredentials: true
})
.post(
    '/cors/req2',
    {
        name: '章三',
    }
);

后端修正如下:

router.post('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:3000");
    res.setHeader("Access-Control-Allow-Headers", "user_token,content-type");
    res.setHeader("Access-Control-Allow-Credentials", true);
    res.send('呼应成功-1');
});
router.options('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:3000");
    res.setHeader("Access-Control-Allow-Headers", "user_token,content-type");
    res.setHeader("Access-Control-Allow-Credentials", true);
    res.send('');
});

点击发送恳求后,咱们发现,恳求主动带着了cookie。

一个事例教你运用“跨域资源共享”

CORS过程中,怎么设置OPTIONS预检恳求的缓存时长?

这个就直接说结论了,篇幅有些过长,就不跟着写代码了,想要实践的小伙伴能够自行实践。

设置 Access-Control-Max-Age字段就能够了,这个字段的单位是 “秒”。

CORS过程中,前端怎么拿到其他的恳求头字段?

不知道咱们有没有重视过一个现象,咱们一般都会用axios来进行通信。可是,在呼应拦截器里,咱们会发现,这儿的头字段并不总是全的,如下:

一个事例教你运用“跨域资源共享”

咱们真实的呼应头字段却有很多个,如下:

一个事例教你运用“跨域资源共享”

针对这一个现象,假设前端想要获取到额定的呼应头字段,后端就需求设置Access-Control-Expose-Headers呼应头字段

就比方,前端想要在拦截器里获取 Etag 字段,这个字段用来判别 资源是否缓存失效的一个指标,后端做出修正如下:

router.post('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:3000");
    res.setHeader("Access-Control-Allow-Headers", "user_token,content-type");
    res.setHeader("Access-Control-Allow-Credentials", true);
    res.setHeader("Access-Control-Expose-Headers", "X-Powered-By,Etag");
    res.send('呼应成功-1');
});
router.options('/req2', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:3000");
    res.setHeader("Access-Control-Allow-Headers", "user_token,content-type");
    res.setHeader("Access-Control-Allow-Credentials", true);
    res.setHeader("Access-Control-Expose-Headers", "X-Powered-By,Etag");
    res.send('');
});

此刻咱们再console一下呼应拦截器,咱们会发现,Etag字段就能够获取到了。

一个事例教你运用“跨域资源共享”

最终

好啦,本期共享到这儿就结束啦,期望我的共享能够对你有帮助,咱们下期再见啦,拜拜~~

重视大众号:熬夜学前端,获取更多干货实践,欢迎沟通共享。