Nginx

发布于 更新于

AI总结: 本文介绍了如何在Nginx中使用Lua脚本捕获请求和响应的头部及体,并通过配置白名单来控制日志输出。该配置包括在不同范围内(http, server, location)设置变量,以便于记录关心的接口信息,避免日志过多。代码分为几个部分:初始化变量、捕获请求头和请求体、响应体过滤、以及日志记录。建议将Lua代码单独放在logs.conf文件中,并通过include指令引入,以提高可维护性和清晰度。

可以将配置放到http, server, location下, 用于不同范围
需修改白名单whitelist, 只打印关心的接口, 防止日志太多

    # 初始化变量  
    set $req_headers "";  
    set $req_body "";  
    set $resp_headers "";  
    set $resp_body "";  

    access_by_lua_block {  
        -- 捕获请求头  
        local headers = ngx.req.get_headers()  
        local headers_str = ""  
        for k, v in pairs(headers) do  
            headers_str = headers_str .. "  " .. k .. ": " .. v .. "\n"  
        end  
        ngx.var.req_headers = headers_str  

        -- 捕获请求体  
        ngx.req.read_body()  
        local body = ngx.req.get_body_data()  
        if not body then  
            local file = ngx.req.get_body_file()  
            if file then  
                local f = io.open(file, "rb")  
                body = f:read("*all")  
                f:close()  
            end  
        end  
        ngx.var.req_body = body or "-"  
    }  

    body_filter_by_lua_block {  
        local chunk = ngx.arg[1]  
        if chunk then  
            ngx.var.resp_body = (ngx.var.resp_body or "") .. chunk  
        end  
    }  

    log_by_lua_block {  
        -- 定义白名单 URI  
        local whitelist = {  
            ["/translate"] = true,  
            ["/test2"] = true  
        }  
        -- 获取当前请求的 URI  
        local uri = ngx.var.uri  
        -- 检查是否在白名单中  
        if whitelist[uri] then  
            local resp_headers = ngx.resp.get_headers()  
            local headers_str = ""  
            for k, v in pairs(resp_headers) do  
                headers_str = headers_str .. "  " .. k .. ": " .. v .. "\n"  
            end  
            ngx.var.resp_headers = headers_str  

            local log_entry = string.format(  
                "\nRequest: %s\nHeaders: \n%sBody: %s\n\nResponse Status: %s\nHeaders: \n%sBody: %s\n",  
                ngx.var.request,  
                ngx.var.req_headers,  
                ngx.var.req_body,  
                ngx.var.status,  
                ngx.var.resp_headers,  
                ngx.var.resp_body or "-"  
            )  

            ngx.log(ngx.INFO, log_entry)  
        else  
            ngx.log(ngx.INFO, uri)  
        end  
    }  

将代码单独放logs.conf文件中, 然后通过include引入
include /data/nginx/conf.d/include/logs.conf;

# 初始化变量  
set $req_headers "";  
set $req_body "";  
set $resp_headers "";  
set $resp_body "";  

access_by_lua_block {  
    -- 捕获请求头  
    local headers = ngx.req.get_headers()  
    local headers_str = ""  
    for k, v in pairs(headers) do  
        headers_str = headers_str .. k .. ": " .. tostring(v) .. "\n"  
    end  
    ngx.var.req_headers = headers_str  

    -- 捕获请求体  
    ngx.req.read_body()  
    local body = ngx.req.get_body_data()  
    if not body then  
        local file = ngx.req.get_body_file()  
        if file then  
            local f = io.open(file, "rb")  
            body = f:read("*all")  
            f:close()  
        end  
    end  
    ngx.var.req_body = body or ""  
}  

body_filter_by_lua_block {  
    local content_type = ngx.header["Content-Type"] or ""  
    -- 只保留文本或 JSON  
    local is_text = content_type:find("^text/", 1, true)          -- text/*  
    local is_json = content_type:find("application/json", 1, true)  
    -- 如果不是文本/JSON,直接返回 [blob]  
    if not is_text and not is_json then  
        ngx.arg[1] = "[blob]"  
        ngx.arg[2] = true   -- 标记为最后一块,结束流  
        return  
    end  
    -- 否则继续累积原始内容  
    local chunk = ngx.arg[1]  
    if chunk then  
        ngx.var.resp_body = (ngx.var.resp_body or "") .. chunk  
    end  
}  

log_by_lua_block {  
    local log_entry = string.format(  
        "========================================\n%s\n%s\n%s\n\nResponse: %s\n%s\n=====================================",  
        ngx.var.request,  
        ngx.var.req_headers,  
        ngx.var.req_body,  
        ngx.var.status,  
        ngx.var.resp_body or ""  
    )  

    ngx.log(ngx.ALERT, log_entry)  
}