跨域资源共享 CORS 错误解析及解决方法

2022-05-08 21:45:31 浏览数 (3)

我们通常会利用CORS机制实现跨域接口服务的访问,为了简便开发环境、测试环境等不同环境的配置,通常大家会用*通配符标识允许任意域名的请求。但是在需要发送Cookie等身份凭证的情况,用*通配符会出现一些错误

首先理解CORS区分简单请求和预检请求两种常见,预见请求首先使用 OPTIONS 方法发起一个预检请求到服务器

用来获知服务器是否允许该实际请求

当我们设置xhr请求 withCredentials: true ,或者fetch请求 credentials: 'include' ,要发送Cookie等身份凭证,设置*通配符时,会认为*为普通字符串,而不是通配符,导致允许规则不匹配,无法正常访问跨域资源

简单请求的异常情况完全包含在预检请求的异常情况内,下面将列出预检请求异常错误及解决方法

Access to XMLHttpRequest at 'http://192.168.1.7:3123/api' from origin 'http://192.168.1.7:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Koa解决方法示例

代码语言:javascript复制
// ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Origin', ctx.headers['origin'] || '*');

Access to XMLHttpRequest at 'http://192.168.1.7:3123/api' from origin 'http://192.168.1.7:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Koa解决方法示例

代码语言:javascript复制
ctx.set('Access-Control-Allow-Credentials', true);

Access to XMLHttpRequest at 'http://192.168.1.7:3123/api' from origin 'http://192.168.1.7:3000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

Koa解决方法示例

代码语言:javascript复制
// ctx.set('Access-Control-Allow-Headers', '*');
ctx.set('Access-Control-Allow-Headers', ctx.headers['access-control-request-headers'] || '*');

这里就是获取到预检请求中Access-Control-Request-Headers的值,再设置为允许的headers。这样子不代码写死允许哪些headers保证各个服务都可以用

Access to XMLHttpRequest at 'http://xxxxx' from origin 'http://yyyyy' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

这种情况是预检请求发生了重定向,可以试下在请求地址中增加/,比如请求地址为 http://a.cn/api?m=n ,调整请求地址为 http://a.cn/api/?m=n

完整Koa示例代码

代码语言:javascript复制
ctx.set('Access-Control-Allow-Methods', '*');
ctx.set('Access-Control-Expose-Headers', '*');
// ctx.set('Access-Control-Allow-Origin', '*');
// ctx.set('Access-Control-Allow-Headers', '*');
ctx.set('Access-Control-Allow-Origin', ctx.headers['origin'] || '*');
ctx.set('Access-Control-Allow-Headers', ctx.headers['access-control-request-headers'] || '*');
ctx.set('Access-Control-Allow-Credentials', true);
// console.log('headers:', ctx.headers);
console.log('cookies uin:', ctx.cookies.get('uin'));
ctx.body = { code: 0 };

以上基本罗列所有出错的情况,示例代码为Koa版本,不同的后端服务,获取header头字符串的大小写可能有差异

从安全方面考虑,这种允许任何地址访问的方式,不要使用在生产环境中!

参考资料:

跨源资源共享(CORS)

Access-Control-Allow-Headers

通过fetch看跨域:是谁阻止了跨域请求?

1 人点赞