关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言
作为一名开发者,你是否经常在浏览器的 Network
面板里,看到一个神秘的 OPTIONS
请求总是抢在你真正的 API 请求之前?它来去匆匆,有时成功,有时失败,留下一个让人头疼的 CORS
错误便扬长而去。
你是否曾对此感到困惑:"这个多余的请求到底是谁发的?为什么要有它?我该怎么让它消失?" 别担心,你并不是一个人。这个看似多余的"预请求"(Preflight Request
),其实是浏览器保护我们应用安全的关键"守门员"。

本文将带你彻底揭开 OPTIONS
请求的神秘面纱,从它的诞生原因到完美解决方案,让你不仅知其然,更知其所以然,从此轻松搞定跨域难题!
02 产生的原因
预请求OPTIONS
的产生源于浏览器的同源策略,这是浏览器最基本的安全功能。同源策略限制了不同源之间的资源交互,防止恶意网站窃取数据。
然而,现代Web
应用需要与不同域的API
进行通信,这就产生了矛盾。尤其现在已经进入了移动时代,前后端分离是无法避开这样的问题:跨域 。CORS
机制应运而生,在安全和功能之间取得平衡,也是解决跨域问题的关键技术。
跨域的前提下,并非所有请求都会触发预检。满足以下所有条件的请求属于 简单请求,不会触发预检:
- 方法为:GET、HEAD、POST
- 头信息仅包含:
Accept
,Accept-Language
,Content-Language
,Content-Type
(值仅限于application/x-www-form-urlencoded
,multipart/form-data
,text/plain
) - 请求中的任何
XMLHttpRequestUpload
对象均没有注册任何事件监听器。
反之,都称为复杂请求,如:
- 使用了非简单方法:PUT、DELETE、PATCH 等。
- 自定义请求头 :如
Authorization
、X-token
等 - Content-Type 超出简单范围 :
application/json
这时,浏览器就会主动发起预请求 OPTIONS,以确保服务器理解和允许接下来的正式请求,从而保护服务器免受非法的跨域请求。
对于前端开发者而言,OPTIONS
请求是由浏览器自动处理的,无需编写额外代码。对于后端来说,预请求也不需要单独去编写方法,但是需要在CorsFilter
中正确处理OPTIONS
方法。
03 跨域的解决方案
跨域可以再网关层解决,如Nginx
,也可以从服务端解决。我们从服务端的角度介绍几种方案。我们先用浏览器的一个HTML
和服务模拟跨域请求。

通过自定义请求头,模拟复杂请求,触发预请求。
3.1 @CrossOrigin
注解

这种方式是细粒度的控制每一个方法。

3.2 SpringBoot
配置

这里要说的就是allowedOrigins
和allowedOriginPatterns
的区别。测试的时候发现配置allowedOrigins("*")
是不生效的。
allowedOrigins
:只能配置固定的请求源,不能使用通配符allowedOriginPatterns
:就是allowedOrigins
扩展,可以使用通配符,可以动态控制允许的源。
3.3 CorsFilter
全限定类名:org.springframework.web.filter.CorsFilter

配置基本一致,其中CorsConfiguration.ALL
就是*
。
3.4 自定义过滤器

配置
java
@Bean
public FilterRegistrationBean apiFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new ApiFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
之前介绍的三种,预请求基本不会有问题,就算有问题也不好解决。自定义的跨域拦截器更加灵活。如果里面的尤其的业务逻辑,如果出现异常,就是导致预请求失败。这时我们需要特殊处理。增加如下的代码:
java
String method = request.getMethod();
if (StringUtils.equalsIgnoreCase(method, "OPTIONS")) {
response.setStatus(204);
return;
}
表示只要是与请求,直接响应2xx,预请求就会通过。204
表示响应成功,但是没有任何内容。
04 小结
总而言之,那个总是在你"非简单请求"前抢先一步的 OPTIONS
请求,并非多此一举,而是浏览器恪尽职守、严格执行安全策略的表现。
为了减少此类请求带来的资源消耗,我们可以通过设置Access-Control-Max-Age
或者maxAge
来控制指定时间段内读取缓存。

案例里面为了方便,放行了所有的请求方法、源以及请求头。在实际生产中为了安全,我们可以按需信任并放行指定的资源。
下次再在 Network 里看到它,你大可以会心一笑,因为你已经透彻理解了它背后的安全逻辑,并能轻松地驾驭它。从此,CORS
预检不再是拦路虎,而是你Web开发知识体系里一个牢固的组成部分。