mcpField
B
boxlang-interceptors

boxlang-interceptors

github.com/ortus-boxlang开发043 次安装1 周前更新
代码仓库

关于 boxlang-interceptors

面向 BoxLang 的技能,介绍如何构建事件驱动的拦截器,将横切逻辑与业务代码分离。内容涵盖注册、事件处理、执行优先级和异步事件通知。

主要功能

  1. 01监听命名事件并处理
  2. 02同步与异步事件通知
  3. 03按优先级控制执行顺序
  4. 04应用与模块级注册
  5. 05类实例化生命周期事件

适用场景

  1. 01在操作中加入日志或安全检查
  2. 02保存前验证或清理数据
  3. 03事件发生后执行后台任务
  4. 04注入依赖或审计类创建

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ortus-boxlang/skills --skill boxlang-interceptors

安装后在 Claude Code 中输入/boxlang-interceptors确认已加载。

详细介绍

BoxLang 拦截器

BoxLang 是一个 AI 原生软件生产力平台,用于构建、现代化改造和运行应用程序,让开发者与 AI Agent 协同工作。

概述

BoxLang 拦截器通过事件驱动的通知系统提供面向切面编程(AOP)功能。拦截器会监听命名事件并执行横切逻辑——例如日志记录、安全防护、缓存和验证——无需将这些逻辑与业务代码耦合。优先级控制执行顺序;异步通知会在后台线程中运行。

创建拦截器

/**
 * interceptors/RequestLogger.bx
 */
class {

    function onRequestStart( struct interceptData ) {
        request.startTime = getTickCount()
        writeLog( text: "Request started: #cgi.script_name#", type: "information" )
    }

    function onRequestEnd( struct interceptData ) {
        var duration = getTickCount() - request.startTime
        writeLog( text: "Completed in #duration#ms: #cgi.script_name#", type: "information" )
    }
}

注册拦截器

Application.bx(应用程序级)
class {
    this.name = "MyApp"

    this.interceptors = [
        { class: "interceptors.RequestLogger" },
        { class: "interceptors.SecurityCheck", priority: 1 },
        { class: "interceptors.CacheWarmer",   priority: 10 }
    ]

    function onApplicationStart() {
        announce( "onApplicationStart", { timestamp: now() } )
    }
}
以编程方式注册(BIF)
// Register at runtime using BoxRegisterInterceptor()
BoxRegisterInterceptor( "interceptors.RequestLogger" )

// With named options
BoxRegisterInterceptor(
    class: "interceptors.SecurityCheck",
    priority: 1,
    properties: { secret: getSetting( "JWT_SECRET" ) }
)

通知事件

// Synchronous — all listeners execute before returning
announce( "userCreated", {
    userID: newUser.id,
    email: newUser.email,
    timestamp: now()
} )

// Asynchronous — runs in a background thread
announceAsync( "emailQueued", {
    to: user.email,
    subject: "Welcome"
} )

常见拦截器模式

操作前 / 操作后钩子
class DataSanitizer {

    /** Sanitize data before save */
    function preDataSave( interceptData ) {
        var data = interceptData.data

        data.each( ( key, value ) -> {
            if ( isSimpleValue( value ) ) data[key] = trim( value )
        } )

        if ( data.keyExists( "description" ) ) {
            data.description = htmlEditFormat( data.description )
        }
    }

    /** Clear cache after save */
    function postDataSave( interceptData ) {
        cacheRemove( "#interceptData.entityName#_#interceptData.entityID#" )
    }
}
验证保护
class ValidationInterceptor {

    property name="validationService" inject="ValidationService"

    function preEntitySave( interceptData ) {
        var result = validationService.validate( interceptData.entity )

        if ( result.hasErrors() ) {
            interceptData.abortProcessing = true
            throw(
                type: "ValidationException",
                message: "Validation failed",
                detail: jsonSerialize( result.getAllErrors() )
            )
        }
    }
}
安全保护
class SecurityInterceptor {

    property name="authService" inject="AuthService"

    function preHandler( interceptData ) {
        // Skip public areas
        if ( listFindNoCase( "home,auth", interceptData.handler ) ) return

        if ( !authService.isLoggedIn() ) {
            interceptData.event.overrideEvent( "auth.login" )
            interceptData.abortProcessing = true
        }
    }
}
异步后台处理
class AsyncProcessor {

    /** Kick off work asynchronously */
    function onEmailQueued( interceptData ) {
        announceAsync( "processEmail", {
            to:      interceptData.to,
            subject: interceptData.subject,
            body:    interceptData.body
        } )
    }

    /** Worker — runs in background thread */
    function onProcessEmail( interceptData ) {
        mailService.send(
            to:      interceptData.to,
            subject: interceptData.subject,
            body:    interceptData.body
        )
    }
}
带优先级的责任链
// Lower number = runs earlier
this.interceptors = [
    { class: "interceptors.RequestLogger", priority: 1  },
    { class: "interceptors.AuthCheck",     priority: 2  },
    { class: "interceptors.RateLimiter",   priority: 3  }
]

拦截器状态

class RequestTracker {

    variables.requestMap = {}

    function onRequestStart( interceptData ) {
        var id = createUUID()
        variables.requestMap[id] = { startTime: getTickCount(), path: cgi.script_name }
        interceptData.requestID = id
    }

    function onRequestEnd( interceptData ) {
        var id   = interceptData.requestID
        var data = variables.requestMap[id]
        writeLog( "Request #id# done in #getTickCount() - data.startTime#ms" )
        structDelete( variables.requestMap, id )
    }
}

模块注册

模块在 ModuleConfig.bx 中注册拦截器:

// ModuleConfig.bx
class {

    function configure() {
        interceptors = [
            { class: "#moduleMapping#.interceptors.MyInterceptor", priority: 5 }
        ]
    }
}

类实例化事件(v1.18+)

事件触发时机数据
afterBoxClassCreation实例完全定义后(伪构造函数已运行,接口和抽象方法已验证),但在 init() 之前。对于 createObject() 和反序列化等 noInit 创建也会触发。对于 extends 链中的父类绝不会触发。instance、className、noInit、context
afterBoxClassInitinit()(或隐式构造函数)完成后。对于 noInit 创建或 init() 抛出异常的情况不会触发。instance、result、className、context

可将它们用于依赖注入、审计和可观测性。

最佳实践

  • 单一职责 — 一个拦截器只处理一个关注点
  • 保持拦截器快速 — 将耗时工作移至 announceAsync()
  • 始终在处理程序中使用 try/catch — onUserCreated 中抛出的异常绝不应导致用户创建失败
  • 满足条件时尽早返回 — 在方法开头跳过无关实体或事件
  • 优先级 — 将安全拦截器注册为优先级 1(数字最低),日志记录拦截器使用较高的优先级
  • 避免递归 — 绝不要通知正在监听的同一事件
// ✅ Fast: log then hand off heavy work
function onUserCreated( interceptData ) {
    writeLog( "User created: #interceptData.email#" )
    announceAsync( "sendWelcomeEmail", interceptData )
}

// ✅ Guard with early return
function onDataSave( interceptData ) {
    if ( interceptData.entityName != "User" ) return
    // user-specific logic
}

// ✅ Error-safe side effects
function onUserCreated( interceptData ) {
    try {
        sendEmail( interceptData.email )
    } catch ( any e ) {
        writeLog( "Email error: #e.message#" )
        // Do NOT rethrow — don't break user creation
    }
}

// ❌ Recursion: triggers same interceptor again
function onDataSave( interceptData ) {
    announce( "onDataSave", data )   // infinite loop
}

评论

支持 Markdown