吴化吉的博客

专注Web开发

发布时间:2018-11-23

跨域响应头总结

如何跨域 这篇博文中,记录了跨域的基本概念、JSONP的原理、还有CROS的概念。但这篇博文相对简单,对于CROS只提到了Access-Control-Allow-Origin响应头,其实对于跨域还有更多的响应头,这里复习一下。

Access-Control-Allow-Origin

首先记录还是这个Access-Control-Allow-Origin,这个响应头表明服务器允许跨域访问的域名,只有设置了这个头,跨域时响应才不会被浏览器拦截。这是万里长征第一步。

Access-Control-Allow-Credentials

直接引用mdn的解释:

响应头表示是否可以将对请求的响应暴露给页面。返回true则可以,其他值均不可以。Credentials可以是 cookies, authorization headers 或 TLS client certificates。

这个响应头表明,浏览器拿到响应后,是否把一些关键信息(cookie,authorization headers,TLS client certificates)返回给页面。

关于authorization headers和TLS client certificates,我还没碰到这种场景,但cookie可以值得说说:

我们正常的跨域的情况下,默认是不传递cookie的,什么意思呢?就是服务器设置的cookie,浏览器是不会返给页面的,所以自然也就不存在下次请求会带上cookie这回事!但是设置cookie又是一个很常见的需求,特别是一些需要用户认证的情况下,怎么办呢?

分两步即可做到:

  • 就是设置这个头:Access-Control-Allow-Credentials:true,这样浏览器会把cookie暴露给页面,通俗说就是能正常设置cookie。
  • 页面在发送请求时,为请求对象设置 withCredentials属性为 true。这样cookie才会随请求一起发送。

关于withCredentials这个属性,不管是有原生XMLHttpRequest,还是Fetch Api ,亦或是jQuery,axios,只要发送请求,都可设置这个属性,举一个原生XMLHttpRequest的例子:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send();

需要注意一点: Access-Control-Allow-Credentials 和 Access-Control-Allow-Origin 均设置时,Access-Control-Allow-Origin 不能设置为通配符:*,而是要设置指定站点域名。

预检请求(Preflight request)相关头

为了更好解释下面几个响应头,这里先解释一下预检请求。 根据MDN的定义:一个 CORS 预检请求是用于检查服务器是否支持 CORS 即跨域资源共享。

在某些时候,浏览器在真正发请求前,会发送一个请求试探请求,请求方法为OPTIONS,并且【请求头】中包含这几个的一个或多个:

  • Access-Control-Request-Method 告知服务器,接下来要发的请求方法,比如:POST,GET,UPDATE,DELETE
  • Access-Control-Request-Headers 告知服务器,请求的首部有自定义的请求头
  • Origin 告知服务器,请求来源站点

而服务器则可根据这些请求头来判断,接下来的请求是否可以通过。如果通过则要返回:

  • Access-Control-Allow-Methods 允许请求的方法,也就是请求头中提交的方法:Access-Control-Request-Method中的内容
  • Access-Control-Allow-Headers 允许的自定义请求头,也就是:Access-Control-Request-Headers中的内容

只有在预检请求中,服务器正确响应了,接下来浏览器才会发真正的请求。

何时发预检请求?

前面说到【在某些时候】浏览器会发预检请求,但实际上非常笼统,那具体规则是什么呢? 规则如下,如果同时满足一下两个条件,则不发预检请求(OPTIONS),否则就会发送:

1, 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

2,HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

这里参考阮一峰老师的文章


大概就这样吧