跨域-转>预解析OPTIONS请求

https://www.jianshu.com/p/b55086cbd9af

补充下options请求:

 HTTP的options方法用于获取目的的资源所支持的通信选项。客户端可以对特定的URL使用OPTIONS方法,也可以对整站(通过将URL设置为*)使用该方法。

三大特点:

1.标准 OPTIONS 不发送请求体,不会附带请求数据;

2.成功的返回没有响应体,响应体(Response body)为空。

3.OPTIONS 是一种安全的请求,不会修改服务器资源。

两种用途:

1.检测服务器所支持的请求方法

2.CORS 中的预检请求

几个问题?

1.预检请求有什么作用?

CORS 中的预检请求

在 CORS 机制中,客户端将请求分为了两种:简单请求非简单请求当请求为非简单请求时,就会触发浏览器发送预检请求,这是浏览器的行为。

预检请求会向服务器确认跨域是否允许,服务返回的响应头里有对应字段Access-Control-Allow-Origin来给浏览器判断:如果允许,浏览器紧接着发送实际请求;不允许,报错并禁止客户端脚本读取响应相关的任何东西。

所以,一个 POST 请求并且请求头添加了Content-Type: application/json ,浏览器判定为非简单请求,自己先发一个 OPTIONS 给服务器获取做跨域判定,获取响应后浏览器发现可以跨域,接着就发送真实的 POST。

这里就解答两个问题了,接下来就是为什么预检请求选择了 OPTIONS 呢?

来看预检请求的流程,如果是一个跨域请求,浏览器会自动给该请求带上 Origin 头部,标明当前请求的来源域;服务器判断这个请求是否允许跨域,就会在返回时,选择是否带上 Access-Control-Allow-Origin 头部,最后,浏览器判断 Access-Control-Allow-Origin 就知道,后续请求是否发送。

这个流程中,对预检请求方法的要求:

  1. 不需要带请求体,服务器判断的依据在 Request header 中;
  2. 服务器返回不需要响应体,浏览器判断的依据在 Response header 中;
  3. 请求不会去修改服务器资源,要是一个安全的请求;
  4. 浏览器默认不会缓存,需要每次发送跨域验证;

但是,这里还是有问题:

  1. 既然服务端做了请求限制,而且浏览器判断跨域只和 Access-Control-Allow-Origin 有关,预检请求是否有点多余?
  2. 原生 form 表单可以提交 POST 请求,而且为一个简单请求,很可能修改服务端数据,仅仅依靠 CORS 机制也不安全。(需要在跨域基础上的简单请求,这个简单请求是表单请求,他虽然跨域了,但是不会触发options请求,就还会对服务器的数据可能发生了改动),所以接下来就是要说:

预检请求的意义

浏览器为了安全的数据传输,提出了 CORS 机制,它更像一种授权机制,需要浏览器和服务器共同配合实现,对于没有实现此机制的客户端,比如 curl,是不受限制的:()

 

 上图中,服务器实现很简单,仅仅返回预先定义好的数据,curl 的返回头中也没有和Access-Control-*相关字段,但是返回体中,我们能够看到返回数据,想必解析出来也并不困难。同样的请求在浏览器中就会报错了:

 在cors机制中,服务器肯定有一套专门处理禁止跨域的逻辑,(虽然跨域是浏览器的自我保护行为,但是只是发出去了,浏览器把响应拦截了,既然能发出去,就可能会对服务器数据造成修改,这对服务器来说是不安全的),这些逻辑可能是复杂和高消耗的。如果客户端发送的请求,服务器都要经过一个复杂的逻辑才能知道是否跨域了,服务器的压力和用户体验都不好,所以这时候预检测就应运而生,发送请求前,先发送预检请求询问服务器是否允许跨域,不允许就不发送实际请求,服务器只需要对预检请求进行跨域处理。

这样来看,在 CORS 机制中,发送预检请求是一种保护机制,保护资源不被未授权的请求修改。

和授权服务很像,预检请求通过了,浏览器后续对同一服务的请求,不需要做跨域询问,如果服务端不想支持跨域访问,啥也不用做。

但是重点来了:

form表单为什么即使跨域了也不会触发浏览器的跨域提示 ?

跨域本质是浏览器对响应数据的一种拦截,自我保护,而form表单呢是只提交,不求回报。没有返回数据,自然就不会被浏览器拦截掉,也就不会报跨域错误。ajax提交是需要返回的,也正是因为这个,才有了CSRF跨站攻击。人家直接注入。

form表单为什么不会触发options请求?

对于传统表单请求,都是简单请求(因为form表单只支持get和post)

如enctype =“multipart/form-data”,提交了是一个外域地址,虽然跨域了,但是不会触发触发options检测,因为只有复杂请求才会。也不会提示跨域(源生form表单请求就算跨域也不会触发浏览器的跨域拦截),因为他只提交,不返回。他还是可能会对服务端数据造成修改。所以服务端需要做请求来源限制。意思就是需要后端对来源做限制,如设置白名单。单纯的依靠浏览器自发的OPTIONS也不可靠。因为他不管form表单提交。

原文地址:https://www.cnblogs.com/haoqiyouyu/p/14407476.html