zoukankan      html  css  js  c++  java
  • CORS预检请求详谈

    引言

    最近在项目中因前后端部署不同地方,前端在请求后端api时发生了跨域请求,我们采用CORS(跨域资源共享)来解决跨域请求,这需要前后端的配合来完成。在这一过程中,后端支持了CORS跨域请求后,前端的请求配置可能会调起CORS的preflight请求,也就是我们所说的预检请求。对CORS不太熟悉的可能会很容易忽视掉这个问题。下面就来说说CORS的preflight请求。CORS的基本用法不在本文讨论中,可以参考阮老师的跨站资源共享CORS详解

    CORS prefligt请求

    preflight请求,就是在发生cors请求时,浏览器检测到跨域请求,会自动发出一个OPTIONS请求来检测本次请求是否被服务器接受。一个OPTIONS请求一般会携带下面两个与CORS相关的头:

    • Access-Control-Request-Method : 本次预检请求的请求方法。
    • Access-Control-Request-Headers:本次请求所携带的自定义首部字段。这些字段是导致产生OPTIONS请求的一个原因。后面会讲到。

    这样,服务端收到该预检请求后,会返回与CORS相关的响应头。主要会包括下面几个,但可能还会有其他的有关CORS字段:

    • Access-Control-Allow-Origin: 服务器允许的跨域请求源
    • Access-Control-Allow-Methods: 服务器允许的请求方法
    • Access-Control-Allow-Headers : 服务器允许的自定义的请求首部字段

    服务器通过CORS跨域请求后,下面浏览器就会发生正式的数据请求。整个请求过程其实是发生了两次请求:一个预检请求,通过后的实际数据请求。这些都可以在浏览器网络请求中看到。可以参考下图:

    需要注意的是:

    1、在上面的两次请求中,预检请求只是一个检查的过程,它不会携带任何请求的参数;预检通过后的请求才会真正的携带请求参数与服务器进行数据通信。

    2、若服务器对预检请求没有任何响应,那么浏览器不知道服务器是否支持CORS而不会发送后续的实际请求;或者服务器不支持当前的Origin跨域访问也不会发送后续请求。

    发生preflight请求的条件

    上面的预检请求并不是CORS请求的必须的请求过程,在一定的条件下并不需要发生预检请求。那么发生预检请求的条件是什么呢?根据HTTP访问控制(CORS)介绍,其实发生预检请求的条件:是否是简单请求。简单请求则直接发送具体的请求而不会产生预检请求。具体来说如下:

    满足下面的所有条件就不会产生预检请求,也就是该请求是简单请求:

    • 请求方法是GETPOSTHEAD其中任意一个

    • 必须是下面定义对CORS安全的首部字段集合,不能是集合之外的其他首部字段。
      Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width。

    • Content-Type的值必须是text/plainmultipart/form-dataapplication/x-www-form-urlencoded中任意一个值

    满足上面所有的条件才不会发送预检请求,在实际项目中我们的请求格式可能是application/json格式编码,或者使用自定义请求头都会触发CORS的预检请求。

    所以,在项目中是否会触发CORS的预检请求要做到心中有数。

    一个发送的预检请求的列子

    我们拿一个实际发生预检请求的例子来说明整个过程。考虑下面的一个例子:

    var xhr = new XMLHttpRequest();
    var url = 'http://bar.other/resources/post-here/';
    var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
        
    function callCors(){
      if(xhr)
        {
          xhr.open('POST', url, true);
          xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
          xhr.setRequestHeader('Content-Type', 'application/xml');
          xhr.onreadystatechange = handler;
          xhr.send(body); 
        }
    }
    ......
    
    

    上面请求中在请求中添加了自定义首部字段X-PINGOTHER,并且请求的Content-Type值application/xml。因此该请求首先会触发一个预检请求。具体的过程见下图

    通过上图可以看到请求实际产生了2次与服务交互的过程,最后一次会将请求参数传给服务器。这样一个CORS请求过程就完成了。

    需要注意的一个有关CORS的点:

    对于附带身份凭证的请求(即服务器设置Access-Control-Allow-Credentials: true),服务器不得设置 Access-Control-Allow-Origin 的值为“*”。否则请求将会失败。

    个人理解是Cookie还是遵循同源策略的,即使因为这个请求是跨域请求,所以每个Origin的Cookie是不能被其他Origin获取到的,也就是不允许Access-Control-Allow-Origin 的值为“*”。

    参考文献

    1、跨域资源共享 CORS 详解
    2、HTTP访问控制(CORS)
    3、CORS - How do 'preflight' an httprequest?

  • 相关阅读:
    我爱java系列之---【微服务间的认证—Feign拦截器】
    我爱java系列之---【设置权限的三种解决方案】
    581. Shortest Unsorted Continuous Subarray
    129. Sum Root to Leaf Numbers
    513. Find Bottom Left Tree Value
    515. Find Largest Value in Each Tree Row
    155. Min Stack max stack Maxpop O(1) 操作
    painting house
    Minimum Adjustment Cost
    k Sum
  • 原文地址:https://www.cnblogs.com/wonyun/p/CORS_preflight.html
Copyright © 2011-2022 走看看