跨域
@EnableCORS 注解支持
在 Tio-Boot 项目中,如果想让 Controller 的 Action 支持跨域请求 (CORS),可以通过在类或方法上添加 @EnableCORS 注解。
- 类级别跨域支持: 在 Controller 类上添加
@EnableCORS注解,这样类下的所有方法都会自动支持 CORS。 - 方法级别跨域支持: 在具体的 Action 方法上添加
@EnableCORS注解,以实现方法级别的 CORS 控制。
Controller 执行阶段会根据 @EnableCORS 注解添加跨域响应头。需要在登录鉴权之前处理浏览器预检时,可以开启下文的全局 CORS。
使用示例:
import nexus.io.annotation.EnableCORS;
import nexus.io.tio.http.common.HttpRequest;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.annotation.RequestPath;
import nexus.io.tio.http.server.util.Resps;
@RequestPath("/admin-api/system/captcha")
@EnableCORS // 应用于整个类
public class CaptchaController {
@RequestPath("/check")
public HttpResponse check(HttpRequest request) {
HttpResponse response = Resps.json(request, "OK");
return response;
}
}
在上述代码中,CaptchaController 类中的所有方法都支持跨域请求。同时,@EnableCORS 也可以用于单独的方法来实现更细粒度的控制。
CORSUtils
如果想要更高的性能,并且不希望每次都使用 @EnableCORS 注解,可以直接使用 CORSUtils.enableCORS 方法来手动处理跨域逻辑。这样可以避免注解解析的开销,在高并发场景下具有一定的性能提升。
代码示例:
import nexus.io.tio.http.server.util.CORSUtils;
import nexus.io.tio.http.common.HttpRequest;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.tio.http.server.util.Resps;
import nexus.io.tio.http.server.model.HttpCors;
HttpResponse response = Resps.json(request, "OK");
CORSUtils.enableCORS(response, new HttpCors()); // 手动启用跨域支持
通过调用 CORSUtils.enableCORS 方法,可以在任意地方启用跨域支持,并根据需要定制 HttpCors 参数,如设置允许的源、方法和头部信息等。
Tio-Boot 中开启跨域请求
要在 Tio-Boot 中全局开启跨域请求,配置一个参数即可
server.http.response.cors.enable=true
分域部署与登录鉴权
前端和 API 使用不同源时,携带 Authorization 的请求通常先发送 OPTIONS 预检。浏览器通过 Access-Control-Request-Headers: authorization 声明后续使用的请求头,预检本身不携带登录 token。实际 GET 或 POST 仍由认证拦截器校验。
开启全局 CORS 后,框架统一协商预检,适用于 Handler、Controller、Function 和 Groovy 路由:
- 预检同时满足 OPTIONS 方法、非空 Origin 和非空 Access-Control-Request-Method。
- 已知方法路由自动返回 204 和 Allow,Access-Control-Allow-Methods 与 Allow 一致。
- 其余路径的预检在鉴权之前返回 204,使用默认允许方法。预检成功不表示资源存在或用户有权限,实际请求仍可能返回 401、403、404 或 405。
- 显式注册的 OPTIONS Handler 保留优先级,仍执行拦截器与处理器;需要自行安排它的鉴权策略。
- 关闭全局 CORS 后,不启用上述兜底预检处理。已知方法路由的普通自动 OPTIONS 仍可返回 204,但不自动添加 CORS 头。
响应头与自定义限制
CORSUtils.enableCORS(response, cors) 从 response 关联的请求读取 Origin 与预检头,不修改传入的 HttpCors,因此配置可复用。
| 配置 | 响应行为 |
|---|---|
allowOrigin 为 * 且 allowCredentials 为 true | 有 Origin 时回显该 Origin |
| 明确设置 allowOrigin | 保留配置,不替换为请求来源 |
预检且 allowHeaders 为 * | 回显 Access-Control-Request-Headers,明确列出 authorization |
| 明确设置 allowHeaders | 保留配置,不扩大允许的请求头 |
全局 CORS 使用开放的默认来源策略;需要限制前端来源时,应使用明确的来源策略。请求使用 credentials: include 或 withCredentials: true 时,Allow-Origin 不能为 *。Authorization 必须在允许的请求头中明确列出,不能仅依赖通配符。响应的 Vary 会包含 Origin、Access-Control-Request-Method、Access-Control-Request-Headers,并保留已有缓存维度。
以下示例展示手动应用固定来源和请求头配置;全局开放 CORS 会统一设置默认响应头,因此固定来源方案应关闭全局开放配置,并配套处理预检。
import nexus.io.tio.http.common.HttpRequest;
import nexus.io.tio.http.common.HttpResponse;
import nexus.io.tio.http.server.model.HttpCors;
import nexus.io.tio.http.server.util.CORSUtils;
public class CorsResponses {
public static HttpResponse apply(HttpRequest request, HttpResponse response) {
HttpCors cors = new HttpCors();
cors.setAllowOrigin("https://cloud.example.com");
cors.setAllowCredentials("true");
cors.setAllowHeaders("authorization, content-type");
cors.setAllowMethods("GET, POST, OPTIONS");
CORSUtils.enableCORS(response, cors);
return response;
}
}
部署验证
curl -i -X OPTIONS 'https://api.example.com/api/user' \
-H 'Origin: https://cloud.example.com' \
-H 'Access-Control-Request-Method: GET' \
-H 'Access-Control-Request-Headers: authorization'
开启全局 CORS 后,该预检应返回 204,允许来源与请求的 Origin 一致,允许头包含 authorization。随后使用新登录获取的完整 token 验证 GET;不带 token 的 GET 仍应返回 401。更新框架后,需要重新打包应用并重启后端,才能让线上请求使用新的处理逻辑。
协议参考:Fetch CORS。
CORS 配置仅影响跨域协商,不改变连接保持或关闭策略。连接行为见 HTTP 请求与连接生命周期。
