精准识别不合规跨域跨页请求需在netty或filter早期阶段,基于origin、sec-fetch-site、referer等无状态校验,用threadlocal+预编译规则实现零锁判定,403即时响应并异步审计。

直接用原生线程安全方式拦截不合规跨域跨页请求,关键不在“拦”,而在“精准识别+无状态决策+不拖慢主流程”。自研微服务框架通常已具备请求生命周期钩子(如 preHandle / filter chain),真正要做的,是把校验逻辑下沉到最轻量、最可控的环节——比如 Netty ChannelHandler 或 Servlet Filter 的 early phase,并确保校验本身不依赖共享可变状态。
明确哪些请求算“不合规跨域跨页”
先别急着写代码,得定义清楚拦截边界:
- 跨域:Origin 头存在且与当前服务允许的域名列表(如配置项 cors.allowed-origins)不匹配,或 Origin 为 null / file:// / chrome-extension:// 等非 Web 页面常见非法来源
- 跨页:不是同源单页应用(SPA)内部的 API 调用,而是从其他 HTML 页面发起的表单提交、iframe 嵌入、window.open 跳转等——可通过检查 Sec-Fetch-Site(值为 cross、none)、Referer(非空但非本域)、X-Requested-With 缺失等组合判断
- 不合规:满足上述任一条件,且请求方法非 OPTIONS(预检放行)、响应头未提前设置 Access-Control-Allow-Origin、或携带了敏感凭证(Credentials: true)但 Origin 是通配符 *
用 ThreadLocal + 预编译规则实现零锁校验
避免 synchronized 或 ReentrantLock —— 拦截器每秒可能执行数万次,锁是性能杀手。正确做法是把校验逻辑做成纯函数式、无副作用:
- 将白名单域名、禁用协议列表、fetch site 映射规则等全部加载进 static final ConcurrentHashMap 或 Guava Cache,只读不改
- 用 ThreadLocal 缓存一次解析结果(如 Origin URI、Referer Host),避免重复 parse;每次请求 init 时 set,finally clear
- 对 Origin 做标准化处理:统一转小写、去掉末尾 /、拒绝含端口的非开发环境 Origin(生产环境不允许 localhost:8080 这类)
在 Filter 中早于业务逻辑做响应裁决
不要等 Controller 执行完再拦截——那已经浪费了 DB 查询、RPC 调用等资源。在标准 Servlet Filter 的 doFilter() 开头就完成判定:
- 提取关键 header,调用校验工具类(无外部依赖、无日志打点、无异常抛出)
- 若不合规,直接 response.setStatus(403) + response.getWriter().write("Forbidden"),然后 return
- 务必调用 response.flushBuffer() 并返回,防止后续 filter 或 servlet 继续写响应体
- 对预检请求(OPTIONS)单独放行,但需验证 Access-Control-Request-Method 是否在白名单中
记录与可观测性:不记日志,但留痕可查
高频拦截不能打 INFO/DEBUG 日志(IO 和 GC 压力大),但要保留审计能力:
- 用高性能 RingBuffer(如 LMAX Disruptor)异步落库一条结构化记录:traceId、ip、origin、referer、method、blockedAt(毫秒级时间戳)
- 暴露 /actuator/blocked-requests 接口,按分钟聚合统计拦截数、Top origin、Top referer,供运维快速感知攻击苗头
- 对连续 5 次被拦的 IP,自动注入到本地限流器黑名单(内存 Map + 定时清理),无需中心化存储











