如何处理跨域时的 OPTIONS 请求?

最近在公司项目中与后端联调时遇到了一个很奇怪的问题,前端发出的 DELETE 方法的 Ajax 请求传到服务端就变成了 OPTIONS 请求。由于服务端没有针对 OPTIONS 请求作回应,此时返回的 http 状态码为 405,意为“方法不被允许”(Method not allowed),DELETE 请求自然也是失败。上网查了一番,原理是触发了 W3C 规定的跨域请求时的安全机制。

W3C 规范中的定义如下:

To protect resources against cross-origin requests that could not originate from certain user agents before this specification existed a preflight request is made to ensure that the resource is aware of this specification. The result of this request is stored in a preflight result cache.

大意就是出于安全考虑,保护资源不接受来自特定客户端的跨域请求,存在预请求来提前通知资源。而具体做法呢?看下面:

It gets slightly more complicated if the resource author wants to be able to handle cross-origin requests using methods other than simple methods. In that case the author needs to reply to a preflight request that uses the OPTIONS method and then needs to handle the actual request that uses the desired method (DELETE in this example) and give an appropriate response.
服务端想要处理使用简单方法之外的方法进行的跨域请求时,需要对使用OPTIONS方法的预请求进行响应,然后才能处理实际请求。

所谓简单方法,是指:

  • 只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。
  • 不会使用自定义请求头(类似于 X-Modified 这种)。

OPTIONS 是 HTTP/1.1 里的方法,用来获取更多服务器端的信息,是一个不应该对服务器数据造成影响的方法。通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能。

到这里,我们对整个情况就很明了了:当 Ajax 跨域请求时,如果 HTTP 方法是非简单方法,则客户端即浏览器会发出 OPTIONS 方法的预请求去询问服务端,在得到允许性质的回应后,才会发送真正的请求;如果服务端对预请求拒绝,则真正的 DELETE 请求等不会发出。

看到这里,相信各位也知道如何解决该问题了:服务端对 OPTIONS 预请求给出允许回应。不过,需要注意的是,不应该满足所有的 OPTIONS 请求,否则这一安全措施便形同虚设了。最好是建立一套验证机制,对符合条件的客户端请求给出允许回应。至于如何实现,就靠我们的后端小伙伴啦。有兴趣的朋友可以查看 MDN 上的这篇文档:HTTP访问控制(CORS)

其他参考文献: