Skip to content

跨域 ​

@EnableCORS 注解支持 ​

在 Tio-Boot 项目中,如果想让 Controller 的 Action 支持跨域请求 (CORS),可以通过在类或方法上添加 @EnableCORS 注解。

  1. 类级别跨域支持: 在 Controller 类上添加 @EnableCORS 注解,这样类下的所有方法都会自动支持 CORS。
  2. 方法级别跨域支持: 在具体的 Action 方法上添加 @EnableCORS 注解,以实现方法级别的 CORS 控制。

Controller 执行阶段会根据 @EnableCORS 注解添加跨域响应头。需要在登录鉴权之前处理浏览器预检时,可以开启下文的全局 CORS。

使用示例:

java
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 方法来手动处理跨域逻辑。这样可以避免注解解析的开销,在高并发场景下具有一定的性能提升。

代码示例:

java
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 会统一设置默认响应头,因此固定来源方案应关闭全局开放配置,并配套处理预检。

java
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;
  }
}

部署验证 ​

bash
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 请求与连接生命周期。

MIT Licensed