在我们的日常使用中,会直接在 Nginx 配置一些拦截规则,而被拦截的请求不会单独记录日志,例如我的香港中转服务器依然使用 NAXSI 进行基础过滤。如果规则有误则很难排查问题,在研究雷池的拦截页面后,我按照雷池的记录拦截 ID 的思路,使用 LUA 编写了一段代码以完成我的需求。需要注意,Nginx 必须安装了 LUA 模块才能使用此代码,Tengine 和 Openresty 已经默认安装 LUA 模块,执行 nginx -V (大写) 检查是否安装了 LUA 模块。
local function generate_unique_id()
-- 生成一个基于时间和随机数的唯一ID
local time_in_ms = ngx.now() * 1000
local random_num = math.random(10000, 99999)
return string.format("%s-%s", time_in_ms, random_num)
end
local function log_request_and_generate_hash()
-- 使用Nginx的变量获取请求IP
local client_ip = ngx.var.custom_x_real_ip
local request_time = os.date("%Y-%m-%d %H:%M:%S", ngx.time())
local request_url = ngx.var.request_uri
local user_agent = ngx.var.http_user_agent
local host = ngx.var.http_host
-- 生成唯一的错误ID
local error_id = generate_unique_id()
-- 使用Lua的table和concat函数生成一个简单的哈希
local hash_table = {host,client_ip, request_time, request_url, user_agent, error_id}
local hash_value = table.concat(hash_table, "|")
-- 返回请求信息、哈希值和错误ID
return host,client_ip, request_time, request_url, user_agent, hash_value, error_id
end
-- 获取当前状态码
local status = ngx.var.status
-- 检查状态码是否为418
if status == "418" then
-- 记录请求并生成哈希
local host,client_ip, request_time, request_url, user_agent, hash_value, error_id = log_request_and_generate_hash()
-- 打开文件以追加模式
local file, err = io.open("/www/err/418/error.log", "a")
if not file then
ngx.log(ngx.ERR, "无法打开文件 /www/err/418/error.log: ", err)
return
end
-- 记录请求信息、哈希值和错误ID
-- 记录哈希值和错误ID
local log_entry = string.format("%s\n", hash_value)
local success, err = file:write(log_entry)
if not success then
ngx.log(ngx.ERR, "无法写入文件 /www/err/418/error.log: ", err)
return
end
file:close()
-- 读取418.html文件内容
local error_file, err = io.open("/www/err/418.html", "r")
if not error_file then
ngx.log(ngx.ERR, "无法打开文件 /www/err/418.html: ", err)
return
end
local file_content = error_file:read("*a")
error_file:close()
-- 在错误页面中添加错误ID的注释
file_content = file_content .. "\n<!-- event_id: " .. error_id .. " -->"
-- 输出418.html文件内容和错误ID
ngx.say(file_content)
else
ngx.log(ngx.ERR, "状态码不是418,当前状态码为: ", status)
end
论坛没有 LUA 的着色)
需要确保 /www/err/418.html 和日志目录 /www/err/418/error.log 真实存在,418 状态码为我自定义的拦截代码,该代码为一个愚人节玩笑而非非,I'M A TEAPOT,虽然 418 状态码在 RFC 7231 中并未明确定义,但它仍然被 4xx(客户端错误)类别所覆盖。然而,这个状态码并不是用来严肃对待的,也不会对客户端或 SEO 产生实质性影响。这个状态码在实际应用中很少使用,但在一些特定的情况下,开发者可能会使用它来进行一些特殊的处理。例如,如果服务器收到了一个无法处理的请求,它可能会返回 418 状态码,表示 "我是茶壶,找咖啡壶去"。这就是说,这个请求应该由其他能够处理的服务器(咖啡壶)来处理。使用 418 状态码为了不影响 403 页面的正常响应。
在 418.html 中,使用如下 JavaScript 代码获取拦截 ID:
<script>
//此处为获取访客IP
async function getIPInfo() {
const response = await fetch('https://api.gymxbl.com/ip/get');
const data = await response.json();
return data;
}
function ipinfo() {
getIPInfo().then(data => {
const li = document.getElementById('ip-info');
li.textContent += `${data.cip} Location: ${data.clo}`;
});
}
function setEventIDAndType() {
var nodes = document.getElementsByTagName("body")[0].childNodes;
var fit2inserts = null;
for (var i = 0; i < nodes.length; i++) {
if (
nodes[i].nodeType == 8 &&
nodes[i].data.trimLeft().startsWith("event_id")
) {
fit2inserts = nodes[i];
}
}
try {
var inserts =
document.getElementsByTagName("html")[0].nextSibling || fit2inserts;
var insertsData = inserts && (inserts.data || "");
var incertDataList = insertsData.split(" ");
var getVal = function (key) {
return incertDataList[incertDataList.indexOf(key + ":") + 1];
};
var event_id = getVal("event_id");
var type = getVal("type");
// var anymore = getVal('anymore') // 新增参数示例
} catch (e) {
console.log(e);
}
if (event_id) {
document.getElementById("EventID").innerText = "你的ID(•ω•):" + event_id;
}
if (type) {
document.getElementById("TYPE").innerText = "TYPE: " + type;
}
}
// 使用addEventListener添加事件监听器
window.addEventListener('load', function() {
ipinfo();
setEventIDAndType();
});
//这一段基本是从雷池的拦截页抄的
</script>
接下来在希望向访客展示错误的地方将 ID 填入: id="ip-info" id="EventID"
<div class="md:flex min-h-screen main-body">
<div class="w-full md:w-1/2 bg-white flex items-center justify-center left-sec">
<div class="max-w-sm m-8 content-body">
<div class="text-black text-5xl md:text-15xl font-black">访问被拦截了哦 ヽ(*。>Д<)o゜</div>
<p class="text-grey-darker text-2xl md:text-3xl mb-7 leading-normal">
</p>
<p class="sub-header">
<h1>好好反省为什么会被拦截叭!(ノ`Д)ノ</h1>
</p>
<br>
<br>
我是一个茶壶!I'm a teapot!
<div class="sub-footer">
<div class="w-full h-2 bg-grey-light my-3 md:my-6"></div>
<ul>
<p></p>
<li id="EventID"></li>
<br>
<li id="ip-info">你的IP: </li>
<br>
<li>发生时间: <script type="text/javascript">
document.write(Date())
</script>
</li>
<br>
<li>拦截由 Lua 脚本</li>
</ul>
</div>
</div>
</div>
<div class="relative pb-full md:flex md:pb-0 md:min-h-screen w-full md:w-1/2 right-sec">
</div>
</div>
此 HTML 仅为示例,使用时需要自行定制。
部署 Nginx
在你希望应用该页面的域名所属 Server 块中添加:
location = /418.html
{
#交给LUA处理
content_by_lua_file /www/lua/418.lua;
#禁止外部访问,404错误码
error_page 404 /404.html;
#仅允许内部访问
internal;
}
#哦对了别忘了把errpage加上,特意回来加一句.....
error_page 418 /418.html;
重启 Nginx 使能生效。。。
我是搞不明白的 本文转自:https://dalao.net/thread-25718.htm
暂无评论