跨域-转>预解析OPTIONS请求
https://www.jianshu.com/p/b55086cbd9af
补充下options请求:
HTTP的options方法用于获取目的的资源所支持的通信选项。客户端可以对特定的URL使用OPTIONS方法,也可以对整站(通过将URL设置为*)使用该方法。
三大特点:
1.标准 OPTIONS 不发送请求体,不会附带请求数据;
2.成功的返回没有响应体,响应体(Response body)为空。
3.OPTIONS 是一种安全的请求,不会修改服务器资源。
两种用途:
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 就知道,后续请求是否发送。
这个流程中,对预检请求方法的要求:
- 不需要带请求体,服务器判断的依据在 Request header 中;
- 服务器返回不需要响应体,浏览器判断的依据在 Response header 中;
- 请求不会去修改服务器资源,要是一个安全的请求;
- 浏览器默认不会缓存,需要每次发送跨域验证;
但是,这里还是有问题:
- 既然服务端做了请求限制,而且浏览器判断跨域只和
Access-Control-Allow-Origin
有关,预检请求是否有点多余? - 原生 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表单提交。