4 / 11 详讲cors跨域资源共享

前面的话

前端日问,巩固基础,不打烊!!!

解答

之前小柒也总结过九种跨域方法(里面有相关实例),这篇文章参考阮一峰老师的文章详细梳理一下cors。

简述

cors - 跨域资源共享,需要浏览器和服务器同时支持, 这种通信方式原理其实就是通过自定义http的头部来进行通信。

两种请求
  • 简单请求:比如POSTGETHEAD
  • 非简单请求:比如PUTDELET或者Content-Type字段类型为application/json
简单请求

如果是简单请求的,浏览器直接发出CORS请求,会自动带上Origin字段(指定请求来自哪个域名)。

当服务端收到响应后:

  • 如果Origin指定的源不在服务器允许的范围内,那么服务端会返回一个正常的HTTP回应。但是这个响应是不带Access-Control-Allow-Origin字段的,浏览器发现响应头没有包含这个字段,就知道出错了,就会抛出一个错误。(这个错误是由XMLHTTPRequest的onerror回调函数捕获的)。

  • 如果Origin指定的源在服务器允许的范围内,那么服务端返回的响应头就会带上。Access-Control-Allow-Origin字段,指定为Origin字段的值,或者是* 表示接受任意域名的请求。(这个字段是必须的

    还可以携带其他的字段:比如Access-Control-Allow-Credentials(允许携带cookie) 、Access-Control-Expose-Headers(允许XMLHTTPRequest对象的getResponseHeader()拿到响应头的其他字段的值)。

跨域如何携带cookie

如果想要携带cookie,必须浏览器与服务器同时支持

  • 浏览器必须开启XMLHTTPRequest对象的WithCredentials属性值为true.

     xhr.withCredentials = true;// 前端设置是否带cookie
    
  • 服务器响应头要携带Access-Control-Allow-Credentials字段的值为true.

      // 允许携带cookie
      res.setHeader('Access-Control-Allow-Credentials', 'true');
    

注意:如果携带了cookie,那么服务器的Access-Control-Allow-Origin字段就不能设置为*,必须指明的域名。

非简单请求
预检请求

如果是非简单请求,那么正式的CORS通信前,会进行一次预检请求。浏览器会先询问服务器,当前请求的域名是否被服务器所允许,如果服务器允许的话,才会进行正式的通信。

看一段浏览器的脚本文件:

var  url = "http://localhost:8084";
var xhr = new XMLHTTPRequest();
xhr.open("PUT",url,true);
// 设置自定义请求头字段:name
xhr.setRequestHeader('name',"xiaoqi")
xhr.send();

浏览器发现这是一个非简单请求,就会自动发出一个预检请求,预检请求的方法是OPTIONS。

针对上面的脚本,对应预检请求头信息:

OPTIONS /cors HTTP/1.1
Origin: http://localhost:8081
Access-Control-Request-Method: PUT 
Access-Control-Request-Headers:name
Connection:keep-alive

可以看到,除了Origin字段外,还包括两个特殊的字段:Access-Control-Request-Method该字段必须,用来列出浏览器CORS请求会用到的HTTP请求方法)、Access-Control-Request-Headers(指定浏览器CORS请求会额外发送的头信息字段)

预检请求回应

服务器相应的头信息设置,服务器设置,哪些域名可以访问,支持的方法,是否可以携带cookie等

  		// 设置哪个源可以访问我
        res.setHeader('Access-Control-Allow-Origin', origin);
        // 允许携带哪个头来访问我
        res.setHeader('Access-Control-Allow-Headers', 'name');
        // 允许哪个方法访问我
        res.setHeader('Access-Control-Allow-Methods', 'PUT');
        // 允许携带cookie
        res.setHeader('Access-Control-Allow-Credentials', 'true');
        // 预检的存在时间
        res.setHeader('Access-Control-Max-Age',6);
        // 允许返回的头
        res.setHeader('Access-Control-Expose-Headers', 'name');

当服务器收到预检请求之后,会检查OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段后,如果允许,就会做出回应:

响应头会带上的字段有:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8081 
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: name
Access-Control-Allow-Credentials: true
...

如果预检请求没有被通过,服务器会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会知道服务器不同意这次预检,返回一个错误,被XMLHttpRequest对象的onerror回调函数捕获 。

正常请求

服务器通过预检请求,以后每次浏览器正常CORS请求,都会和简单请求一样,会有一个Origin字段,服务器的回应也会有Access-Control-Allow-Origin头信息字段

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值