worker_processes 1; error_log stderr warn; pid /tmp/nginx.pid; events { worker_connections 1024; } http { include /usr/local/openresty/nginx/conf/mime.types; default_type application/json; access_log /dev/stdout; sendfile on; keepalive_timeout 65; client_max_body_size 10M; # Lua 共享字典用于缓存 lua_shared_dict data_cache 10m; server { listen 80; server_name _; # CORS 配置 add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, X-Password' always; # OPTIONS 请求 if ($request_method = 'OPTIONS') { return 204; } # 健康检查 location = /health { access_log off; return 200 '{"status":"ok"}'; add_header Content-Type application/json; } # 登录页面 location = /login { root /usr/local/openresty/nginx/html; try_files /login.html =404; } # 登录API location = /api/login { content_by_lua_block { local cjson = require "cjson" ngx.req.read_body() local body = ngx.req.get_body_data() local ok, data = pcall(cjson.decode, body) if ok and data.password == "admin123123123" then ngx.header["Set-Cookie"] = "auth=verified; Path=/; Max-Age=604800" ngx.status = 200 ngx.say(cjson.encode({success = true})) else ngx.status = 401 ngx.say(cjson.encode({error = "Invalid password"})) end } } # 静态文件(需要认证) location / { access_by_lua_block { local cookie = ngx.var.http_cookie if not cookie or not string.match(cookie, "auth=verified") then return ngx.redirect("/login") end } root /usr/local/openresty/nginx/html; index index.html; } # POST /api/data - 上传/更新数据 location = /api/data { content_by_lua_block { local cjson = require "cjson" local method = ngx.req.get_method() -- GET 请求:列出所有 tag if method == "GET" then -- 读取索引文件 local index_file = io.open("/data/index.json", "r") if not index_file then ngx.status = 200 ngx.say(cjson.encode({tags = {}})) return end local index_content = index_file:read("*all") index_file:close() local ok, index = pcall(cjson.decode, index_content) if not ok then ngx.status = 500 ngx.say(cjson.encode({error = "Invalid index file"})) return end -- 计算状态 local now = os.time() for tag, item in pairs(index.tags) do if item.expires_at then local expires_time = os.time({ year = tonumber(item.expires_at:sub(1, 4)), month = tonumber(item.expires_at:sub(6, 7)), day = tonumber(item.expires_at:sub(9, 10)), hour = tonumber(item.expires_at:sub(12, 13)), min = tonumber(item.expires_at:sub(15, 16)), sec = tonumber(item.expires_at:sub(18, 19)) }) if expires_time < now then item.status = "expired" elseif (expires_time - now) < 172800 then -- 2 days item.status = "expiring_soon" else item.status = "valid" end else item.status = "no_expiry" end end ngx.status = 200 ngx.say(cjson.encode(index)) return end -- POST 请求:上传数据 if method == "POST" then -- 读取请求体 ngx.req.read_body() local body = ngx.req.get_body_data() if not body then ngx.status = 400 ngx.say(cjson.encode({error = "Empty body"})) return end -- 解析 JSON local ok, data = pcall(cjson.decode, body) if not ok then ngx.status = 400 ngx.say(cjson.encode({error = "Invalid JSON"})) return end -- 验证密码 if data.password ~= "admin123123123" then ngx.status = 401 ngx.say(cjson.encode({error = "Invalid password"})) return end -- 验证必填字段 if not data.tag or not data.type or not data.data then ngx.status = 400 ngx.say(cjson.encode({error = "Missing required fields: tag, type, data"})) return end -- 生成文件名(tag 中的特殊字符替换为 _) local filename = data.tag:gsub("[^%w%-]", "_") .. ".json" local filepath = "/data/" .. filename -- 添加时间戳 local timestamp = os.date("%Y-%m-%d %H:%M:%S") if not data.metadata then data.metadata = {} end if not data.metadata.created_at then data.metadata.created_at = timestamp end data.metadata.updated_at = timestamp -- 计算过期时间 if data.metadata.expires_in then local expires_at = os.time() + data.metadata.expires_in data.metadata.expires_at = os.date("%Y-%m-%d %H:%M:%S", expires_at) end -- 移除密码字段 data.password = nil -- 保存数据文件 local file = io.open(filepath, "w") if not file then ngx.status = 500 ngx.say(cjson.encode({error = "Failed to save file"})) return end file:write(cjson.encode(data)) file:close() -- 更新索引 local index_file = io.open("/data/index.json", "r") local index = {tags = {}} if index_file then local index_content = index_file:read("*all") index_file:close() local ok, parsed = pcall(cjson.decode, index_content) if ok then index = parsed end end -- 更新或添加 tag(tags是对象,直接赋值) if not index.tags then index.tags = {} end index.tags[data.tag] = { tag = data.tag, type = data.type, file = filename, created_at = index.tags[data.tag] and index.tags[data.tag].created_at or data.metadata.created_at, updated_at = timestamp, expires_at = data.metadata.expires_at } -- 保存索引 index_file = io.open("/data/index.json", "w") if index_file then index_file:write(cjson.encode(index)) index_file:close() end ngx.status = 200 ngx.say(cjson.encode({ success = true, message = "Data saved", tag = data.tag, timestamp = timestamp })) return end -- 其他方法不支持 ngx.status = 405 ngx.say(cjson.encode({error = "Method not allowed"})) } } # GET /api/data/copy/:tag - 一键复制格式 location ~ ^/api/data/copy/([^/]+)$ { content_by_lua_block { local cjson = require "cjson" local tag = ngx.var[1] -- 生成文件名 local filename = tag:gsub("[^%w%-]", "_") .. ".json" local filepath = "/data/" .. filename -- 读取数据 local file = io.open(filepath, "r") if not file then ngx.status = 404 ngx.say(cjson.encode({error = "Tag not found"})) return end local content = file:read("*all") file:close() local ok, data = pcall(cjson.decode, content) if not ok then ngx.status = 500 ngx.say(cjson.encode({error = "Invalid data file"})) return end -- 生成复制文本 local copy_config = { serverUrl = "http://47.122.126.244:5001", password = "admin123123123", tag = tag, type = data.type } local copy_text = cjson.encode(copy_config) ngx.status = 200 ngx.say(cjson.encode({ copy_text = copy_text, formatted = "```json\\n" .. copy_text .. "\\n```" })) } } # GET /api/data/:tag - 获取数据 # DELETE /api/data/:tag - 删除数据 location ~ ^/api/data/([^/]+)$ { content_by_lua_block { local cjson = require "cjson" local tag = ngx.var[1] local method = ngx.req.get_method() -- 生成文件名 local filename = tag:gsub("[^%w%-]", "_") .. ".json" local filepath = "/data/" .. filename -- DELETE 请求 if method == "DELETE" then -- 验证密码 local password = ngx.var.http_x_password if password ~= "admin123123123" then ngx.status = 401 ngx.say(cjson.encode({error = "Invalid password"})) return end -- 删除文件 os.remove(filepath) -- 更新索引 local index_file = io.open("/data/index.json", "r") if index_file then local index_content = index_file:read("*all") index_file:close() local ok, index = pcall(cjson.decode, index_content) if ok then -- tags 是对象,直接删除key if index.tags and index.tags[tag] then index.tags[tag] = nil end index_file = io.open("/data/index.json", "w") if index_file then index_file:write(cjson.encode(index)) index_file:close() end end end ngx.status = 200 ngx.say(cjson.encode({ success = true, message = "Data deleted", tag = tag })) return end -- GET 请求 if method == "GET" then -- 验证密码 local password = ngx.var.http_x_password if password ~= "admin123123123" then ngx.status = 401 ngx.say(cjson.encode({error = "Invalid password"})) return end -- 读取数据 local file = io.open(filepath, "r") if not file then ngx.status = 404 ngx.say(cjson.encode({error = "Tag not found"})) return end local content = file:read("*all") file:close() ngx.status = 200 ngx.say(content) return end -- 其他方法不支持 ngx.status = 405 ngx.say(cjson.encode({error = "Method not allowed"})) } } } }