对前端来讲跨域应该是不陌生的,解决跨域的方案有不少种。而我司前端接口调用也正是CORS的方式,因此不免在联调阶段会碰见一些CORS跨域的问题,下面经过一个简单的demo验证一下CORS解决跨域的过程当中,对一些不清楚的知识点作一个简单的总结html
示例 demo 已经放在GitHub 上, 其中目录client文件夹托管客户端代码、server目录做为处理CORS的服务端,分别把两端的代码跑起来,就能够进行CORS相关配置的学习了前端
对CORS的了解能够先看下一下阮老师的这两篇文章:ios
一、浏览器同源政策及其规避方法
二、跨域资源共享CORS详解git
假设你已经了解服务端处理CORS跨域时,会配置相关的一些响应头,以下:github
Access-Control-Allow-Credentials: true,
Access-Control-Allow-Origin: *,
Access-Control-Allow-Headers: 'header',
Access-Control-Expose-Headers: 'serve-header',
Access-Control-Allow-Methods: 'methods',
Access-Control-Max-Age: '1800', // 30min = 1800s
复制代码
那这些响应头都具体是神马做用呢? 下面会结合demo来了解各参数的配置做用,并给出结果图。express
做用:服务端容许跨域的源,也就是浏览器的输入的地址。demo中为:http://huoyun-test.djtest.cn
包括端口号80,80端口默认省略了。axios
若是把server端的origin改成: http://huoyun-online.djtest.cn
, 当发送请求的时候,浏览器包以下错误: 后端
如上图由请求头和响应头以及控制台(一、二、3)三点得出:因为CORS策略,经过浏览器预检请求options得出源Origin对应的url不在CORS跨域容许的范围类,所以呢,服务端应该设置对应的页面域名http://huoyun-test.djtest.cn
,这样才不会报这样的错误。api
做用:携带cookie跨域
若是调用接口过程当中,须要cookie的传递,则须要设置这个参数为true,而且Access-Control-Allow-Origin就不能设为星号*,必须指定明确的、与请求网页一致的域名。 若是前端采用axios来请求接口时,需同时设置axios.defaults.withCredentials = true;
这里若是设置 Access-Control-Allow-Origin: *
,会报以下的错误:
axios.defaults.withCredentials=true;
,浏览器也会包相似的错误:
即当浏览器经过XMLHttpRequest对象发送请求时,设置了withCredentials属性为true时,对应的服务端此时须要作相应的处理。
所以当先后端在CORS跨域出现问题时,经过修改demo来验证就能够很好的找到答案了,而不是百度了一遍,依然是处于茫然中,不知道要让服务端干吗,同时做为前端应该怎么作,不让本身此时成为前端小白,有话可说...
做用:先后端须要经过header来进行数据交互时,须要设置使用到的header字段。
如前端经过设置请求头header中的字段axios.defaults.headers.common['client-header'] = 1;
, 若是此时Access-Control-Allow-Headers字段没有设置对应的header字段,浏览器会报以下错误:
也就是说经过前端设置的自定义header字段,须要服务端在Access-Control-Allow-Headers字段中设置对应的header
做用:容许浏览器端可以获取相应的header值
若是服务端接口设置了响应头字段res.setHeader('serve-header','from->express');
可是CORS中对应的字段Access-Control-Expose-Headers并无处理,此时经过请求响应后的header结果以下:
能够看到虽然响应头里面有serve-header
字段,可是却获取不到, 若是设置了 Access-Control-Allow-Headers: serve-header
再来看下结果
此时则能够拿到服务端设置的响应头里面的serve-header
字段了
做用:控制发送预检请求options的频率
一、若是设置Access-Control-Max-Age: 0
, 则发送请求的时候浏览器始终都会先发送预检请求options。如图
每次点击send cors按钮请求接口 api/getcors
时,都会发送options预检请求
二、若是设置Access-Control-Max-Age: 1800
, //预请求缓存30分钟=1800秒 结果以下:
点击send cors按钮请求接口 api/getcors
时,只会首次发送options预检请求,接着后面再次请求时就不会发options请求了
三、在2的基础上,若是你的Chrome浏览器在debug状态,勾选上Disable cache,也是失效的 以下:
即每次都会发送预检请求
四、这里强调一下Access-Control-Max-Age:1800
设置缓存时间,仅仅是针对已经请求过的接口如api/getcors
,当点击按钮send cors2 第一次请求接口api/getcors2
时,一样也会发送预检请求options
做用:请求方法的限制
这里最后一个参数就留给读者你去校验了,修改下Access-Control-Allow-Methods 参数看看浏览器的报错结果,体会一下...
到这里6个参数就总结完了,下面补充一下CORS跨域时,cookie的携带过程
首先Cookie操做具备不可跨域特性,如:
// client 端设置
Cookies.set('cookie-value', '1', { domain: 'huoyun-test.djtest.cn' });
Cookies.set('cookie-value', '2', { domain: 'test.djtest.cn' });
Cookies.set('cookie-value', '3', { domain: 'djtest.cn' });
// server 端设置
res.setHeader('Set-Cookie', 'cookie-value=22;domain=.test.djtest.cn;path=/');
复制代码
打开chrom调试工具:以下
即:页面huoyun-test.djtest.cn
不能够操做test.djtest.cn
的cookie,经过document.cookie读取的时候是能够获取到从一级域名djtest.cn
及如下的全部子域的cookie值,而在面板中是看不见服务端设置的cookie-value=22;domain=.test.djtest.cn;path=/
的值,这里注意下!!!
那此时再请求接口api/getcors
,服务端接受到的cookie值以哪一个为准呢 ? 以下:
即:最终解析到的cookie会以client端一级域名设置的值Cookies.set('cookie-value', '3', { domain: 'djtest.cn' });
为准
对于express中间件cors、以及cookie-parser的解析代码都不复杂,想了解的同窗,欢迎clone demo下来debug一下,印象会深入点
一、浏览器同源政策及其规避方法
二、跨域资源共享CORS详解
三、如何区分不一样用户——Cookie/Session机制详解
四、关于cookie的深刻了解