openresty-minifiers

openresty-minifiers - 由 OpenResty Inc. 开发的高性能压缩库,支持压缩 HTML、CSS 和 JavaScript 文件。

名称

openresty-minifiers - 由 OpenResty Inc. 开发的高性能压缩库,支持压缩 HTML、CSS 和 JavaScript 文件。

本库依赖私有库 replace-filter-plus 模块。

返回目录

目录

说明

OpenResty Minifiers 包含三个压缩器,分别用于优化不同类型的网页内容:

  • JS 压缩器:用于压缩 JavaScript 文件。通过移除不必要的空白字符、换行符和注释,减小文件体积,加快网页加载速度。
  • CSS 压缩器:与 JS 压缩器类似,用于压缩 CSS 文件。通过移除不必要的字符和空格来优化样式表,加快页面渲染速度。
  • HTML 压缩器:用于压缩 HTML 文件。通过移除冗余的 HTML 标签、空白字符和注释,减少带宽占用,加快页面加载速度。

这些压缩器是支持流式处理的专有 Nginx 输出过滤器模块。其时间复杂度严格为 O(n),其中 n 为响应体数据流的长度;空间复杂度严格为 O(1),即无论输入大小如何,内存用量都保持恒定。

基准测试

这些压缩器使用专有的正则表达式编译器,该编译器基于我们自主研发的 DFA 优化算法。

在我们的基准测试中,JS-minifier 模块在 Core i9-13900K 的单个 CPU 核心上可达到 120 MB/s 以上的扫描速度。它支持使用固定大小的缓冲区(例如 8KB)进行流式处理。

基准测试结果见:https://openresty.org/misc/re/bench/。

返回目录

使用示例

在 OpenResty 配置文件的 http 块中加载 replace-filter-plus 模块,然后在 init_by_lua_block 块中加载 openresty-minifiers 模块。

http {
    ...
    load_module /usr/local/openresty/nginx/modules/ngx_http_replace_filter_module.so;

    init_by_lua_block { require "resty.replace" }
    ...

}

可以根据需要加载 min-js.so、min-html.so 和 min-css.so,分别用于压缩 JavaScript、HTML 和 CSS 文件:

js-minifier

http {
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-js.so
        /usr/local/openresty-minifiers/tpls/min-js.tpl;

    server {

        ...
        location ~ \.js$ {
            replace_filter_types application/javascript;
            replace_filter_max_buffered_size 8k;
            access_by_lua_block {
                local ok, err = require "resty.replace".pick("min-js")
                if not ok then
                    error("failed to pick replace prog: " .. err)
                end
            }
        }
    }
}

返回目录

html-minifier

http {
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-html.so
        /usr/local/openresty-minifiers/tpls/min-html.tpl;

    server {

        ...

        location ~ \.html$ {
            replace_filter_types text/html;
            replace_filter_max_buffered_size 8k;
            access_by_lua_block {
                local ok, err = require "resty.replace".pick("min-html")
                if not ok then
                    error("failed to pick replace prog: " .. err)
                end
            }
        }
    }
}

返回目录

css-minifier

http {
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-css.so
        /usr/local/openresty-minifiers/tpls/min-css.tpl;

    server {

        ...

        location ~ \.css$ {
            replace_filter_types text/css;
            replace_filter_max_buffered_size 8k;
            access_by_lua_block {
                local ok, err = require "resty.replace".pick("min-css")
                if not ok then
                    error("failed to pick replace prog: " .. err)
                end
            }
        }
    }
}

返回目录

安装

配置软件仓库

首先,需要配置二进制包仓库。按照以下命令进行配置。(将命令中的 CLIENT_TOKEN 替换为订阅邮件中的有效令牌)

curl -o get-xray-priv-lib-repo.sh https://pkg2.openresty.com/scripts/get-xray-priv-lib-repo.sh

sudo bash get-xray-priv-lib-repo.sh -l openresty-minifiers -t CLIENT_TOKEN

安装软件包

注意:以下安装说明适用于 OpenResty 1.21.4.x。

对于使用 yum 包管理器的操作系统,运行以下命令安装私有库。

sudo yum install -y openresty-minifiers replace-filter-plus-nginx-module-1.21.4

对于使用 dnf 包管理器的操作系统,运行以下命令安装私有库。

sudo dnf install -y openresty-minifiers replace-filter-plus-nginx-module-1.21.4

对于使用 apt 包管理器的操作系统,运行以下命令安装私有库。

sudo apt-get install -y openresty-minifiers replace-filter-plus-nginx-module-1.21.4

返回目录

指令

以下指令由 openresty-minifiers 依赖的 replace-filter-plus 模块提供。

返回目录

replace_filter_preload

语法: replace_filter_preload <so_path> <templatefile>;

默认值: 无

上下文: http


加载由 or-regex 预先生成的 .so 文件和模板文件,并在初始化阶段将其插入哈希表。提取 so_path 中的文件名并去除扩展名,作为哈希表的键。

示例如下:

http {
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-html.so /usr/local/openresty-minifiers/tpls/min-html.tpl;
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-css.so /usr/local/openresty-minifiers/tpls/min-css.tpl;
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-js.so /usr/local/openresty-minifiers/tpls/min-js.tpl;
}

例如,从 /usr/local/openresty-minifiers/lib/min-html.so 中提取 min-html 作为哈希表的键。

模板文件格式如下:

"$&" g
"$&" g
"" g

引号规则应遵循 Nginx 配置文件的字符串语法或类似规则。

返回目录

replace_filter_types

语法: replace_filter_types <mime-type> …

默认值: replace_filter_types text/html

上下文: http, server, location, location if

阶段: 响应体输出过滤阶段

指定需要处理的一种或多种 MIME 类型(由 Content-Type 响应头给出)。

默认只处理 text/html 类型的响应。

Lua 接口显式选择的程序会绕过此检查,调用者必须自行根据响应类型选择合适的程序。

返回目录

replace_filter_max_buffered_size

语法: replace_filter_max_buffered_size <size>

默认值: replace_filter_max_buffered_size 8k

上下文: http, server, location, location if

阶段: 响应体输出过滤阶段

限制模块在运行时缓冲的数据总大小,默认为 8k。

返回目录

replace_filter_last_modified

语法: replace_filter_last_modifiled keep | clear

默认值: replace_filter_last_modified clear

上下文: http, server, location, location if

阶段: 响应体输出过滤阶段

控制如何处理已有的 Last-Modified 响应头。

默认情况下,如果存在 Last-Modified 响应头,模块会将其清除。可以通过以下配置始终保留原有的 Last-Modified 响应头:

    replace_filter_last_modified keep;

返回目录

replace_filter_skip

语法: replace_filter_skip value

默认值: 无

上下文: http, server, location, location if

阶段: 响应头输出过滤阶段

控制是否跳过当前响应的替换。值为空字符串或 "0" 时不跳过,其他值均跳过;支持包含 NGINX 变量的值。

返回目录

Lua API

pick() 在请求的 access 阶段提前选择预加载的程序,随后由模块的 header filter 判断是否实际启用。enable() 在 header_filter_by_lua_block 中根据已经取得的响应头立即判断并启用,适合根据源站返回的 Content-Type 选择压缩器。

项目pick(name)enable(name)
调用阶段access_by_lua_blockheader_filter_by_lua_block
适用场景请求阶段已能确定程序需要根据响应头选择程序
检查响应及调整响应头后续由模块的 header filter 执行调用时立即执行
成功返回值true:仅表示选择成功,最终仍可能跳过true:已启用
跳过或失败返回值nil, err:选择失败false, reason:跳过;nil, err:失败

响应处理条件

  • Lua 选择程序时绕过 replace_filter_types。调用者必须保证程序适合响应的 MIME 类型,不能依赖该指令保护 JSON、图片等响应。
  • 非空 Content-Encoding(例如 gzip)、Content-Length: 0 或值为真的 replace_filter_skip 会使响应跳过替换。跳过时保留响应体及相关响应头。
  • 启用时清除 Content-Length 和 Accept-Ranges;默认清除 Last-Modified,配置 replace_filter_last_modified keep 时保留。
  • 只处理主请求。子请求的响应头、响应体直接透传,配置 replace_filter 的子请求也不执行替换。通过 ngx.location.capture() 捕获原文后,若由主请求输出,仍可在主请求上替换一次。
  • 同一请求只能选择一个程序。A 已启用时,重复调用 enable(A) 返回 true。支持先 pick(A) 再 enable(A);如果 A 尚未启用,则检查响应条件后再激活。选择不同程序仍返回 nil, "current request already set prog"。

在 access 阶段已能确定程序时,使用 pick();需要根据响应头选择程序时,在 header_filter_by_lua_block 中使用 enable(),由接口完成响应检查和响应头调整。

返回目录

find_prog_id(name)

根据 replace_filter_preload 加载的 .so 文件名(去除扩展名)查找程序 ID。例如 min-html.so 对应 min-html。name 必须为字符串,未找到时返回 -1。

返回目录

set_prog_by_id(r, prog_id)

在 access 阶段选择程序。r 是由 require("resty.core.base").get_request() 获得的请求指针,prog_id 是 find_prog_id() 返回的 ID。

成功返回 nil,失败返回错误字符串。子请求返回 "subrequests are not supported",不设置程序。选择成功并不表示响应最终一定会被改写;仍需通过后续的响应检查。

返回目录

pick(name)

pick(name) 是先查找程序 ID、再为当前请求调用 set_prog_by_id() 的便捷接口。只缓存成功的查找。

access_by_lua_block {
    local ok, err = require("resty.replace").pick("min-js")
    if not ok then
        ngx.log(ngx.ERR, "failed to pick minifier: ", err)
    end
}

成功返回 true,失败返回 nil, err,不返回 false。未知名称返回 nil, "replace program not found: <name>";为子请求选择已知程序时返回 nil, "subrequests are not supported"。

返回目录

enable(name)

仅在 header_filter_by_lua_block 中调用。根据当前响应检查跳过条件,成功后立即启用并调整响应头,无需调用者手动删除这些头。

返回值含义
true指定程序已启用,包括调用前已启用的情况。
false, "empty response body"Content-Length 为 0。
false, "response body is content-encoded"Content-Encoding 非空。
false, "replace_filter_skip is true"replace_filter_skip 求值为真。
false, "subrequests are not supported"当前请求是子请求。
nil, err未知程序、程序冲突、非法调用阶段或其他错误。

返回 false 时不选择新程序,也不调整响应头;之前通过 pick() 选择的程序仍保留,但未启用。未知程序返回 replace program not found: <name>;错误调用阶段返回 API disabled in the current context。错误参数类型会抛出 Lua 错误。

指定程序已启用时,重复调用直接返回 true,不会再次检查响应条件或调整响应头。调用仍须位于 header-filter 阶段,且响应头尚未发送。

如果此前尚未选择程序,适用于当前响应的原生 replace_filter 规则优先于 enable(),包括从上层配置继承的规则。无论模块顺序如何,此时调用均返回 nil, "current request already set prog"。如果响应类型不匹配 replace_filter_types,原生规则不会阻止 Lua 启用程序。对于跳过、带内容编码或空响应的情况,仍返回 false, reason。

返回目录

enable_prog_by_id(r, prog_id)

enable() 的按 ID 调用形式。r 和 prog_id 的含义与 set_prog_by_id() 相同;调用阶段、响应检查以及 true / false, reason / nil, err 返回约定与 enable() 相同。非法 ID 返回 nil, "invalid prog id"。

返回目录

根据响应头选择压缩器

下面的示例要求所用版本支持 enable(),并假定过滤模块已加载且上游 backend 已配置。它接受带参数的 MIME 类型(例如 text/css; charset=utf-8),跳过未列出的类型,并使用 enable() 根据最终响应头启用压缩器。发往源站的 Accept-Encoding 被清空;如果源站仍返回编码后的响应,模块会跳过它。

http {
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-html.so
        /usr/local/openresty-minifiers/tpls/min-html.tpl;
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-css.so
        /usr/local/openresty-minifiers/tpls/min-css.tpl;
    replace_filter_preload /usr/local/openresty-minifiers/lib/min-js.so
        /usr/local/openresty-minifiers/tpls/min-js.tpl;

    server {
        location / {
            proxy_set_header Accept-Encoding "";
            proxy_pass http://backend;

            header_filter_by_lua_block {
                local content_type = ngx.header.content_type or ""
                local match = ngx.re.match(content_type, [[^\s*([^;\s]+)]], "jo")
                if not match then
                    return
                end

                local mime = string.lower(match[1])
                local name
                if mime == "text/html" then
                    name = "min-html"

                elseif mime == "text/css" then
                    name = "min-css"

                elseif mime == "text/javascript"
                       or mime == "application/javascript"
                then
                    name = "min-js"

                else
                    return
                end

                local ok, err = require("resty.replace").enable(name)
                if ok == nil then
                    ngx.log(ngx.ERR, "failed to enable minifier: ", err)
                end
            }
        }
    }
}

返回目录

版权与许可

版权所有 (C) OpenResty Inc.,保留所有权利。

本软件为专有软件,严禁以任何形式再分发或共享。

返回目录