Quickeryi / note

学习记录
2 stars 0 forks source link

关于跨域的那些事 #31

Open Quickeryi opened 7 years ago

Quickeryi commented 7 years ago

本章谈谈CORS那些有意思的事

Cross-origin resource sharing

什么是CORS

全称跨域资源共享,它是W3C的一个标准,用来解决跨域问题!

它与JSONP有何不同

  1. jsonp虽然说也是一个标准,但是它不是官方的,而是开发者们依靠自己的聪明才智创造出来的
  2. jsonp只能用在GET请求中,这是一个很大的限制,而CORS可以使用所有的HTTP方法

    如何使用CORS

    要完美的使用CORS依赖于两部分:客户端(浏览器)& 服务端。首先浏览器必须支持CORS,目前来说只有IE10-不支持,同样服务端需要设置需要允许跨域请求并响应。

    CORS请求分类

    CORS的请求分为两种:简单请求(simple request)和非简单请求(not-so-simple request)

整个CORS通信过程,都是浏览器自动完成,不需要开发者在客户端特别设置什么。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息

何为简单请求

一般来说我们使用CORS时都是触发简单请求,满足以下条件的就是简单请求:

1. 请求方法是以下三种之一:
    1)HEAD
    2)GET
    3)POST
         - 仅当POST方法的Content-Type值等于下列之一
            1)text/plain
            2)multipart/form-data
            3)application/x-www-form-urlencoded

2. 不得人为设置除下列集合以外的头部字段
    1)Accept
    2)Accept-Language
    3)Content-Language
    4)Content-Type (注意上述POST请求的限制)
    5)DPR
    6)Downlink
    7)Save-Data
    8)Viewport-Width
    9)Width

对于简单请求,在Request Headers中会新增一个Origin字段,该字段就是指定请求源,如下图: 0a3300aa-f429-4c90-8493-4de4d2d30c31

如果服务端没有对跨域做特殊处理,那么浏览器接收到响应后不会正确处理,而会报错,并且该错误可以被XMLHttpRequest.onerror捕获,如下图所示: 092f3ab6-513e-4f46-bab2-b027cee3f6d4

如何才能让浏览器正确响应 其实很简单,只需要在服务端响应时,设置一个额外的头部信息即可:

Access-Control-Allow-Origin: <origin> | *

HTTP 响应头部字段

除了上述 Access-Control-Allow-Origin 的响应头部字段外,还有一些其他的极其重要的字段

// server res.header('Access-Control-Allow-Credentials', true)

**还需要注意两点:**
1)一旦 `server` 端设置了 `Access-Control-Allow-Credentials` 那么 `Access-Control-Allow-Origin `就不能设置通配符 `*`,否则会报错,如下所示:
![error](https://user-images.githubusercontent.com/25584184/30208144-bb8f3b78-94c4-11e7-8b9d-75c6d1e341f9.png)

2)一旦设置了 `xhr.withCredentials=true`,那么必须设置`Access-Control-Allow-Credentials: true`否则会报错!

- **Access-Control-Expose-Headers**:在`CORS`请求响应中,我们通过`xhr.getResponseHeader `只能拿到一些通用的头部,如果我们想要拿到一些自定义的头部信息,则需要设置`Access-Control-Expose-Headers`,如下所示:
```javascript
// server
res.set({
   'X-Customer-Header-1': '1',
   'X-Customer-Header-2': '2',
   'Access-Control-Expose-Headers': 'X-Customer-Header-1, X-Customer-Header-2'
})

// client
xhr.getResponseHeader('X-Customer-Header-1') // 1

何为非简单请求

非简单请求的说法并不是官方定义的,而是为了区分简单请求而已。

注意:预检请求对于用户来说是透明的,无感知的!

------------------ 未完,接着下面评论 --------------------

Quickeryi commented 7 years ago

Access-Control-Max-Age:大家可能会想,我如果不想每次都发送preflight,而是只是在第一次请求时发送,而后将其缓存住,之后的每次请求都只发送实际请求即可。那么就需要用到这个响应头部,它用来指定preflight请求的结果能够被缓存多久。

小结

讲到这里基本上把关于CORS的一些概念与实践论述清楚了,下面引用两张MDN的图来概括一下吧!

cred-req

课外阅读&参考