跨域系列二:CORS进阶之Preflight请求

一.Access-Control-Allow-Origin

  上一篇跨域系列一:从跨域到CORS文章有说过CORS的基本使用,也实现了跨域的请求。本篇来讲讲CORS更高阶的用法。
  首先来讲讲Access-Control-Allow-Origin的用法。
  Access-Control-Allow-Origin:*表示的是允许任何的来源都可以访问,然而这并不符合大多数人的需求。假如我们只需要固定的一台或几台机器,或者是某个域名下的才可以访问,这又该如何呢?
  还是按照先前的例子,从10.107.98.46:8089的服务跨域到nginx服务10.107.98.46:8088。现在来演示一下,只允许10.107.98.46:8089的访问,在nginx是这样配置的。

  并再次发起请求,是成功的。

  也可以试一下把10.107.98.46:8089前面的http://去掉。

location /AngularTodoMVC {
        add_header 'Access-Control-Allow-Origin' '10.107.98.46:8089';
        proxy_pass   http://10.107.98.46:21240/AngularTodoMVC;
        proxy_redirect off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $http_host;
}

  会发现是不成功的,毕竟不同的协议也是不同的域的。

  下面有个配置可以参考,在nginx中设置域名的访问。

set $cors '';
if ($http_origin ~* 'https?://(localhost|www\.yourdomain\.com|www\.yourotherdomain\.com)') {
        set $cors 'true';
}

if ($cors = 'true') {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
}

  在上面的配置中,$http_origin表示的是获得来源域的域名,也就是请求头Origin的内容。

  

二.Preflight请求
  之前在浏览器模拟跨域请求的js是这样的:

var xhttp = new XMLHttpRequest();
xhttp.open("GET", "http://10.107.98.46:8088/AngularTodoMVC/#/", true);
xhttp.send();

  使用的方法是GET,CORS跟jsonp等方法不一样的,它可以支持像POST,DELETE方法。

  先用POST方法来试一下,是成功的。而改成DELETE方法报错了,大体上说DELETE方法是不被允许的,进一步来看下产生的请求。

  使用DELETE方法时,并不会真正的产生DELETE请求,而是先生成了一个叫OPTIONS的请求。

  这个OPTIONS请求是怎么回事呢?
  这个OPTIONS请求也叫Preflight请求,它是在发起DELETE真实请求时,先询问服务器是否支持DELETE方法,再用响应头信息的方式返回给浏览器,浏览器根据响应信息查看服务器是否支持DELETE方法,如果支持的话,就再发起真实的DELETE方法,不支持就报错了。所以出现了上面的报错信息。
  我们先让服务器支持DELETE方法,再来尝试新的请求。

location /AngularTodoMVC {
  add_header 'Access-Control-Allow-Origin' '*';
  add_header 'Access-Control-Allow-Methods' 'DELETE';
}

  我们发现,发起了两次请求,一次是询问服务器是否支持DELETE方法,响应头信息显示是支持DELETE的,再发起了真实的DELETE方法(虽然我这里的DELETE请求报403,但并不影响我们分析它的过程及配置后已支持DELETE)。

  从前面的分析可以知道,GET,POST是不会发出Preflight请求的,而DELETE方法会,那还有什么情况下会呢?下面列举出来:

  a.使用的方法不是GET、POST或HEAD的任何一种
  b.Content-Type请求来不是下面任何一种

application/x-www-form-urlencoded
multipart/form-data
text/plain

  c.不寻常的请求头,例如不是下面的几种:

Accept
Accept-Language
Content-Language

  d.XMLHttpRequest的upload事件

  值得注意的是,为了避免困惑,在Access-Control-Allow-Methods都会显式地写上GET,POST方法,即使它是默认就支持的。

add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE'

  除此之外,频繁的Preflight请求可能会造成性能的消耗。我们可以用下面的方法处理一下:

add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;

  Access-Control-Max-Age可以设置请求的过期时间,单位是秒(second)。另外,返回204的状态码,是返回一个空内容的返回,毕竟,Preflight请求只需要响应的头部信息(Access-Control-Allow-Methods),并不需要响应内容的。

 

文章来源:http://corsbook.rails365.net/467079

附一前端学习视频地址:https://www.rails365.net/playlists

posted on 2019-01-14 23:15  bijian1013  阅读(1850)  评论(0)    收藏  举报

导航