You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在APISIX serverless-pre-function插件中外置Lua代码?

关于APISIX serverless-pre-function外置Lua代码的配置问题

背景

我正在使用APISIX的serverless-pre-function插件在请求生命周期中执行自定义Lua代码,目前Lua函数直接嵌入JSON配置中,希望将其外置到独立Lua文件以提升可维护性与可读性。

当前可正常运行的配置

{
  "plugins": {
    "serverless-pre-function": {
      "phase": "access",
      "functions": [
        "return function(conf, ctx) local jwt = require('resty.jwt'); local userinfo = ngx.req.get_headers()['x-userinfo']; if userinfo then local jwt_obj = jwt:verify(nil, userinfo); if jwt_obj.payload then local preferred_username = jwt_obj.payload.preferred_username; if preferred_username then ngx.req.set_header('X-User-Uid', preferred_username); else ngx.log(ngx.ERR, 'Claim preferred_username not found in JWT'); end; else ngx.log(ngx.ERR, 'Failed to decode JWT: ', jwt_obj.reason); end; else ngx.log(ngx.ERR, 'No x-userinfo header found'); end; end"
      ]
    }
  }
}

目标

将Lua函数迁移至独立文件(如/usr/local/apisix/lua_scripts/extract_userinfo.lua),并在serverless-pre-function插件配置中引用该文件。

尝试的配置(报错)

{
  "plugins": {
    "serverless-pre-function": {
      "phase": "access",
      "functions": [
        {
          "file": "/usr/local/apisix/lua_scripts/extract_userinfo.lua"
        }
      ]
    }
  }
}

错误信息

{"error_msg":"failed to check the configuration of plugin serverless-pre-function err: property \"functions\" validation failed: failed to validate item 1: wrong type: expected string, got table"}

我的APISIX Docker配置(config.yaml)

apisix:
  node_listen: 9080
  enable_admin: true
  log_level: debug
  lua_module_cache: true
  lua_path: "/usr/local/apisix/lua_scripts/?.lua;;"
  extra_lua_path: /usr/local/apisix/lua_scripts/?.lua
  proxy:
    ssl:
      verify: true
      trusted_ca_certificates: /usr/local/apisix/keycloak-cert.pem
  plugins:    # plugin list
    - authz-keycloak
    - basic-auth
    - clickhouse-logger
    - client-control
    - consumer-restriction
    - cors
    - csrf
    - datadog
    - echo
    - error-log-logger
    - ext-plugin-post-req
    - ext-plugin-post-resp
    - ext-plugin-pre-req
    - fault-injection
    - file-logger
    - forward-auth
    - google-cloud-logging
    - gzip
    - hmac-auth
    - http-logger
    - ip-restriction
    - jwt-auth
    - kafka-logger
    - kafka-proxy
    - key-auth
    - ldap-auth
    - limit-conn
    - limit-count
    - limit-req
    - loggly
    - mocking
    - opa
    - openid-connect
    - opentelemetry
    - openwhisk
    - prometheus
    - proxy-cache
    - proxy-control
    - proxy-mirror
    - proxy-rewrite
    - public-api
    - real-ip
    - redirect
    - referer-restriction
    - request-id
    - request-validation
    - response-rewrite
    - rocketmq-logger
    - server-info
    - serverless-post-function
    - serverless-pre-function
    - skywalking
    - skywalking-logger
    - sls-logger
    - splunk-hec-logging
    - syslog
    - tcp-logger
    - traffic-split
    - ua-restriction
    - udp-logger
    - uri-blocker
    - wolf-rbac
    - zipkin
    - elasticsearch-logger
    - cas-auth
  plugin_attr:
    log-rotate:
      enable_compression: false
      max_kept: 3
      max_size: 10240

deployment:
  admin:
    admin_key:
      - name: "admin"
        key: "admin123"
        role: admin
    allow_admin:
      - 0.0.0.0/0

  etcd:
    host:
      - "http://etcd:2379"

疑问

  1. 如何在serverless-pre-function插件中正确外置Lua代码?
  2. 在配置中引用外部Lua文件的正确方式是什么?
  3. Lua文件有哪些特定要求(如返回值、结构)?
  4. Docker-compose或APISIX Docker配置是否需额外设置?

补充:

  • 运行在Docker容器中
  • Lua文件已放置在/usr/local/apisix/lua_scripts/目录
  • Lua函数嵌入JSON配置时可正常运行

解答

1. 正确外置Lua代码的方法

你遇到的错误是因为当前使用的APISIX版本不支持functions字段中传入{file: ...}格式的对象。旧版本的serverless-pre-function仅支持字符串形式的Lua代码,因此需要通过require语句引入外部Lua文件,将代码逻辑以字符串形式返回。

如果你的APISIX版本是2.10及以上,则原生支持{file: ...}的对象格式,报错大概率是版本不兼容导致,建议检查APISIX版本。

2. 引用外部Lua文件的正确方式

针对旧版本APISIX(不支持对象格式)

修改插件配置为以下形式,通过require加载外部文件:

{
  "plugins": {
    "serverless-pre-function": {
      "phase": "access",
      "functions": [
        "return require('extract_userinfo')"
      ]
    }
  }
}

由于你已经在config.yaml中配置了lua_path: "/usr/local/apisix/lua_scripts/?.lua;;",直接写require('extract_userinfo')即可自动匹配到/usr/local/apisix/lua_scripts/extract_userinfo.lua文件。

针对2.10及以上版本APISIX

你的尝试配置是可行的,确保配置格式正确即可:

{
  "plugins": {
    "serverless-pre-function": {
      "phase": "access",
      "functions": [
        {
          "file": "/usr/local/apisix/lua_scripts/extract_userinfo.lua"
        }
      ]
    }
  }
}

3. Lua文件的特定要求

外部Lua文件必须返回一个接收conf(插件配置)和ctx(请求上下文)两个参数的函数,结构与嵌入时的函数完全一致。示例extract_userinfo.lua内容如下:

local jwt = require('resty.jwt')

return function(conf, ctx)
    local userinfo = ngx.req.get_headers()['x-userinfo']
    if userinfo then
        local jwt_obj = jwt:verify(nil, userinfo)
        if jwt_obj.payload then
            local preferred_username = jwt_obj.payload.preferred_username
            if preferred_username then
                ngx.req.set_header('X-User-Uid', preferred_username)
            else
                ngx.log(ngx.ERR, 'Claim preferred_username not found in JWT')
            end
        else
            ngx.log(ngx.ERR, 'Failed to decode JWT: ', jwt_obj.reason)
        end
    else
        ngx.log(ngx.ERR, 'No x-userinfo header found')
    end
end

核心要求:

  • 必须返回一个函数,参数固定为conf和ctx
  • 依赖库可在文件顶部提前引入,无需在函数内部重复声明
  • 代码逻辑与嵌入时保持一致即可

4. Docker相关配置

(1)目录挂载

确保本地的lua_scripts目录挂载到APISIX容器的/usr/local/apisix/lua_scripts/路径下,否则容器内无法访问外部Lua文件。在docker-compose.yml中添加挂载配置:

services:
  apisix:
    image: apache/apisix:latest
    volumes:
      - ./config.yaml:/usr/local/apisix/conf/config.yaml
      - ./lua_scripts:/usr/local/apisix/lua_scripts  # 挂载本地lua_scripts目录
    ports:
      - "9080:9080"
      - "9180:9180"
    depends_on:
      - etcd

(2)Lua路径配置

你当前的config.yaml中lua_path和extra_lua_path的配置是正确的,确保路径指向/usr/local/apisix/lua_scripts/?.lua即可。

(3)缓存问题

如果修改外部Lua文件后不生效,可临时关闭lua_module_cache(设置为false),或者直接重启APISIX容器,避免Lua模块被缓存。


内容的提问来源于stack exchange,提问作者user3090303

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:27:04