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

使用APISIX插件改写响应时出现乱码非ASCII字符问题

APISIX数据脱敏插件响应乱码问题

我正尝试用Lua为APISIX开发一款数据脱敏插件,参考官方资料编写了自定义插件,也试过官方的response-rewrite插件,但两种方式都得到完全乱码的响应。预期响应是JSON格式:

{
"success": {},
"timeStamp": "2023-12-01 10:03:12.0",
"version": "21.2.0.0"
}

自定义插件的body_filter代码如下:

function _M.body_filter(conf, ctx)
    if conf.filters then

        local body = core.response.hold_body_chunk(ctx)
        if not body then
            return
        end
        
        local err
        for _, filter in ipairs(conf.filters) do
            body, _, err = re_gsub(body, filter.regex, filter.replace, "jo")

            if err ~= nil then
                core.log.error("regex \"" .. filter.regex .. "\" substitutes failed:" .. err)
            end
        end

        ngx.arg[1] = body
        return
    end

end

我尝试在代码里打印获取到的响应体日志,结果日志里也是随机非ASCII字符,说明问题出在获取响应体的环节,而非替换逻辑。


问题原因及解决办法

核心原因:上游响应启用了gzip压缩

如果上游服务返回的响应是gzip压缩后的二进制数据,直接通过core.response.hold_body_chunk获取的话就是乱码,因为没有做解压处理。

解决步骤:

  1. 禁用上游响应的gzip压缩
    在APISIX的路由配置中,给upstream添加headers配置,强制上游返回未压缩的内容:

    upstream:
      headers:
        set:
          Accept-Encoding: "identity"
    

    配置后上游会返回未压缩的文本响应,再进行脱敏处理就不会出现乱码。

  2. 在插件中手动解压响应体
    如果无法修改上游配置,需要在插件中对压缩的响应体进行解压:

    local zlib = require "zlib"
    
    function _M.body_filter(conf, ctx)
        if conf.filters then
            local body = core.response.hold_body_chunk(ctx)
            if not body then
                return
            end
    
            -- 检查响应头中的压缩标识
            local content_encoding = core.response.get_header(ctx, "Content-Encoding")
            if content_encoding and content_encoding == "gzip" then
                -- 初始化gzip解压流
                local inflate, err = zlib.inflate()
                if not inflate then
                    core.log.error("failed to create inflate stream: ", err)
                    return
                end
                -- 执行解压
                local decompressed_body = inflate(body)
                if err then
                    core.log.error("failed to decompress body: ", err)
                    return
                end
                body = decompressed_body
                -- 移除压缩标识头,避免下游收到错误的响应格式
                core.response.set_header(ctx, "Content-Encoding", nil)
                -- 更新响应长度头,避免长度不匹配
                core.response.set_header(ctx, "Content-Length", #body)
            end
    
            local err
            for _, filter in ipairs(conf.filters) do
                body, _, err = re_gsub(body, filter.regex, filter.replace, "jo")
                if err ~= nil then
                    core.log.error("regex \"" .. filter.regex .. "\" substitutes failed:" .. err)
                end
            end
    
            ngx.arg[1] = body
            return
        end
    end
    

    注意:需要确保APISIX已安装lua-zlib依赖,可通过opm install api7/lua-zlib完成安装。

  3. 官方插件的正确配置
    如果使用response-rewrite插件,同样需要确保上游响应未压缩,或者在插件配置中启用解压处理(部分版本支持),同时正确配置替换规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:22:34