由Credentials引起的cors跨域问题
一、问题引入
express搭建服务,使用fetch接口调用显示跨域,具体如下
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
更改服务端cors配置如下:
app.all("*", (req, res, next) => { // 设置允许跨域的域名,*代表允许任意域名跨域 res.header("Access-Control-Allow-Origin", "*"); //允许的header类型 res.header("Access-Control-Allow-Headers", "content-type"); //跨域允许的请求方式 res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS"); if (req.method == 'OPTIONS') res.sendStatus(200); //让options尝试请求快速结束 else next(); })
但是依旧跨域,后来仔细查看跨域错误信息
即:fetch请求设置了 credentials 为 include 时,Access-Control-Allow-Origin
不能为 *
显而易见是由于 Credentials 配置,浏览器发起预检请求时返回错误显示跨域
二、关于Credentials
Access-Control-Allow-Credentials,标志是否允许客户端请求携带Credentials(凭证)。Credentials可以是 cookies, authorization headers 或 TLS client certificates.(一般可能携带cookies的情况比较多)。该响应头只能是true或者不设置!
当作为对预检请求(Option请求)的响应的一部分时,它指示是否可以使用Credentials(凭证)进行实际请求。请注意,若一个对资源的请求带了Credentials,而这个响应头(Access-Control-Allow-Credentials)没有随资源返回,响应就会被浏览器忽视,不会返回到web内容,预检请求也会因此抛出不能通过预检的error。
Access-Control-Allow-Credentials头 工作中与XMLHttpRequest.withCredentials 或Fetch API中的Request() 构造器中的credentials 选项结合使用。Credentials必须在前后端都被配置(即the Access-Control-Allow-Credentials header 和 XHR 或Fetch request中都要配置)才能使带credentials的CORS请求成功. 必需请求和response header都支持
三、使用方式
1.XHR 中使用 Credentials
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://example.com/', true); xhr.withCredentials = true; // 设置withCredentials为true xhr.send(null);
2.JQ 中使用 Credentials
$.ajax({ type:"POST", url: 'http://example.com/', data: {}, xhrFields: { withCredentials: true // 设置withCredentials为true }, crossDomain: true, dataType: 'json', success: successHandler });
3.fetch 中使用 Credentials
fetch控制Credentials的选项有三个:
请求时携带凭证:credentials: 'include'
仅在同源时请求时携带凭证:credentials: 'same-origin'(浏览器默认值,在旧版本浏览器,例如safari 11依旧是omit,safari 12已更改)
不在请求中包含凭证,credentials: 'omit'
fetch(url, { credentials: 'include' })
4.axios 中使用 Credentials
const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // 环境变量base接口地址 url = base url + request url withCredentials: true, // 跨域请求时发送Cookie timeout: 60000, // 请求超时 headers: { "Content-Type": "application/json; charset=UTF-8;" } });
四、服务端配置
response响应需添加
Access-Control-Allow-Credentials: true
express具体配置如下:
app.all("*", (req, res, next) => { console.log('req.headers.origin', req.headers.origin); // 设置允许跨域的域名,*代表允许任意域名跨域 // res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Origin", req.headers.origin); //允许的header类型 res.header("Access-Control-Allow-Headers", "content-type"); //跨域允许的请求方式 res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS"); res.header("Access-Control-Allow-Credentials", true); if (req.method == 'OPTIONS') res.sendStatus(200); //让options尝试请求快速结束 else next(); })
说明:
服务端响应Access-Control-Allow-Credentials(可选) – 表示是否允许发送Cookie,只有一个可选值:true(必为小写)。如果不包含cookies,请略去该项,而不是填写false。这一项与 XmlHttpRequest 对象当中的 withCredentials 属性应保持一致,即 withCredentials 为true时该项也为true;withCredentials 为false时,省略该项不写。反之则导致请求失败。
最后:
要注意,当设置了 Access-Control-Allow-Credentials 为 true 时,Access-Control-Allow-Origin 不能为 * ,也是出于一种安全策略,比如:在cookie中存取的是用户的登录信息,又不限制客户端的请求来源,他人获取到cookie以后则可随意发起请求,登录该用户账号,损害用户权益
参考:https://blog.csdn.net/zSY_snake/article/details/105230125
更多有关跨域和CORS知识请看本博客其他博文:跨域资源共享 CORS 详解 - 盼星星盼太阳 - 博客园 (cnblogs.com)