webapp.lua 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. local md5 = require "md5"
  2. local code = require "code"
  3. local lfsUtil = require "utils.lfsUtil"
  4. local staticfile = require "staticfile"
  5. local protoUtil = require "utils.protoUtil"
  6. local SALT_MD5 = "b8JKMN1UhanX" -- 商城md5 验签
  7. local GAME_SALT_MD5 = "0bdb9a5863c8c9063a42f38a9d5166fe" -- 游戏服加盐 md5
  8. local root = {}
  9. local controllerList = {}
  10. -- 无控制器
  11. local function l_get_unmatch_controller(res)
  12. res.code = 404
  13. res.body = "<html><head><title>404 Not Found Controller </title></head><body> <p>404 Not Found</p></body></html>"
  14. res.headers["Content-Type"] = "text/html"
  15. return res.code, res.body, res.headers
  16. end
  17. -- 无响应函数处理
  18. local function l_get_unmatch_process(res)
  19. res.code = 404
  20. res.body = "<html><head><title>404 Not Found Process </title></head><body> <p>404 Not Found</p></body></html>"
  21. res.headers["Content-Type"] = "text/html"
  22. return res.code, res.body, res.headers
  23. end
  24. -- 服务器内部错误处理
  25. local function serverError(res)
  26. res.code = 500
  27. res.body =
  28. "<html><head><title>Internal Server Error</title></head><body> <p>500 Internal Server Error</p></body></html>"
  29. res.headers["Content-Type"] = "text/html"
  30. return res.code, res.body, res.headers
  31. end
  32. local function l_get_req_headers(isHtml)
  33. local headers = {
  34. ["Access-Control-Allow-Origin"] = "*",
  35. ["Content-Type"] = "application/json",
  36. ["Access-Control-Allow-Methods"] = "POST,GET,OPTIONS",
  37. ["Access-Control-Allow-Credentials"] = true,
  38. ["Access-Control-Allow-Headers"] = "content-type,x-requested-with,x-ui-request,lang"
  39. }
  40. if isHtml then
  41. headers["Content-Type"] = "text/html"
  42. end
  43. return headers
  44. end
  45. local function l_get_math_controller_and_func(path)
  46. path = string.sub(path, 2, -1) -- 去除/
  47. local data = nil
  48. if string.match(path, "_") then
  49. data = string.split(path, "_")
  50. else
  51. data = string.split(path, "/")
  52. end
  53. local controller = table.remove(data, 1)
  54. local func = table.concat(data, "_")
  55. return string.format("%s", controller), func
  56. end
  57. -- 根据协议获取模块
  58. local function _get_cotroller(proto)
  59. local data = string.split(proto, "_")
  60. return data[1]
  61. end
  62. -- 匹配静态资源
  63. local function l_is_match_static(path)
  64. if not IS_TEST then
  65. return false
  66. end
  67. if path == "/" then
  68. path = "/static/index.html"
  69. end
  70. local offset = path:find("/", 2, true)
  71. if not offset then
  72. return false
  73. end
  74. -- 非静态资源
  75. local controller = path:sub(1, offset - 1)
  76. if controller ~= "/static" then
  77. return false
  78. end
  79. -- 读取静态文件
  80. local filename = path:sub(offset + 1)
  81. local content = staticfile[filename]
  82. if content then
  83. return true, 200, content
  84. end
  85. return true, 404, "404 Not found"
  86. end
  87. -- 匹配GM后台
  88. local function l_is_match_gm_json(path)
  89. local offset = path:find("json")
  90. if not offset then
  91. return false
  92. end
  93. return true, "/sgm_interface"
  94. end
  95. local function l_pack_rsp(errCode, resData)
  96. local res = {code = errCode, data = resData}
  97. return cjson_encode(res)
  98. end
  99. local function l_pack_gm_rsp(errCode, resData)
  100. resData = resData or {}
  101. resData.code = errCode or -1
  102. return cjson_encode(resData)
  103. end
  104. -- 请求
  105. local function GET(path, query)
  106. local isStatic, errCode, body = l_is_match_static(path)
  107. if isStatic then
  108. return errCode, body, l_get_req_headers(true)
  109. end
  110. local isGmJson, pathData = l_is_match_gm_json(path)
  111. if isGmJson then
  112. path = pathData
  113. body = body or query.body
  114. local ok, data = pcall(cjson_decode, body)
  115. if not ok then
  116. log.error("get params %s", tostring(body))
  117. body = nil
  118. else
  119. body = data
  120. end
  121. end
  122. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  123. local controllerName, method = l_get_math_controller_and_func(path)
  124. local controller = controllerList[controllerName]
  125. if not controller then
  126. log.error("controller[%s] not exist", controllerName)
  127. return l_get_unmatch_controller(res)
  128. end
  129. local func = controller[method]
  130. if not func then
  131. log.error("controller[%s] has no method[%s] ", controllerName, method)
  132. return l_get_unmatch_process(res)
  133. end
  134. local errCode, ret = func(body or query)
  135. if isGmJson then
  136. res.body = l_pack_gm_rsp(errCode, ret)
  137. else
  138. res.body = l_pack_rsp(errCode, ret)
  139. end
  140. return res.code, res.body, res.headers
  141. end
  142. local function l_get_gm_param(body)
  143. local function split(str, reps)
  144. local res = {}
  145. str:gsub(
  146. "[^" .. reps .. "]+",
  147. function(w)
  148. table.insert(res, w)
  149. end
  150. )
  151. return res
  152. end
  153. local query = {}
  154. for index, value in ipairs(split(body, "&")) do
  155. for k, v in value:gmatch("([^=]+)=([^=]+)") do
  156. query[k] = v
  157. end
  158. end
  159. return query
  160. end
  161. local function POST(path, body, response)
  162. local isStatic, errCode, sbody = l_is_match_static(path)
  163. if isStatic then
  164. return errCode, sbody, l_get_req_headers(true)
  165. end
  166. local data = cjson_decode(body)
  167. local name = data.name
  168. log.info("POST body[%s] name[%s]", tostring(body), tostring(name))
  169. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  170. local controllerName = _get_cotroller(name)
  171. local controller = controllerList[controllerName]
  172. if not controller then
  173. log.error("controller[%s] not exist", controllerName)
  174. return l_get_unmatch_controller(res)
  175. end
  176. local func = controller[name]
  177. if not func then
  178. log.error("controller[%s] has no method[%s] ", controllerName, method)
  179. return l_get_unmatch_process(res)
  180. end
  181. local isGmJson = controllerName == "gm"
  182. local param = isGmJson and data.data or l_get_gm_param(body)
  183. local errCode, ret = func(param)
  184. if isGmJson then
  185. res.body = l_pack_gm_rsp(errCode, ret)
  186. else
  187. res.body = l_pack_rsp(errCode, ret)
  188. end
  189. return res.code, res.body, res.headers
  190. end
  191. local function OPTIONS(body)
  192. local headers = l_get_req_headers()
  193. headers["Content-Type"] = nil
  194. return 200, body, headers
  195. end
  196. local function ERROR()
  197. return 200, l_pack_rsp(code.REQUEST_NOT_FOUND), l_get_req_headers()
  198. end
  199. local function SPROTO(name, args, response)
  200. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  201. local controllerName = _get_cotroller(name)
  202. local controller = controllerList[controllerName]
  203. if not controller then
  204. log.error("SPROTO controller[%s] not exist", controllerName)
  205. res.body = response({code = code.REQUEST_NOT_FOUND})
  206. return res.code, res.body, res.headers
  207. end
  208. local func = controller[name]
  209. if not func then
  210. log.error("SPROTO controller[%s] has no name[%s] ", controllerName, name)
  211. res.body = response({code = code.REQUEST_NOT_FOUND})
  212. return res.code, res.body, res.headers
  213. end
  214. local errCode, resData = func(args)
  215. resData = resData or {}
  216. resData.code = errCode
  217. res.body = response(resData)
  218. return res.code, res.body, res.headers
  219. end
  220. -- 解析请求参数
  221. local function l_decode_sproto(ip, headers, path, body)
  222. if path ~= "/pb" then
  223. return
  224. end
  225. local sz = headers["content-length"] or #body
  226. local ok, pType, pName, args, response = protoUtil:decode_c2s_req(body, sz)
  227. if not ok then
  228. return
  229. end
  230. -- pName = pName:gsub("_", "/")
  231. -- pName = string.format("/%s", pName)
  232. if headers and headers["proxy-client-ip"] then
  233. ip = headers["proxy-client-ip"]
  234. end
  235. args.ip = ip
  236. return "SPROTO", pName, args, response
  237. end
  238. local function l_is_match_sign(path, query, body)
  239. log.info("l_is_match_sign path[%s] query[%s]", tostring(path), tostring(query))
  240. local salt = ""
  241. local sign = query.sign
  242. if path == "/pb" then
  243. salt = GAME_SALT_MD5
  244. elseif path == "/json" then
  245. salt = SALT_MD5
  246. end
  247. log.info("l_is_match_sign salt[%s]", tostring(salt))
  248. if not sign then
  249. return false
  250. end
  251. local genSign = md5.sumhexa(body .. salt)
  252. log.info("l_is_match_sign genSign[%s]", tostring(genSign))
  253. if genSign == sign then
  254. return true
  255. end
  256. return false
  257. end
  258. -- 初始化
  259. function root:init()
  260. local files = lfsUtil:get_path_lua_files("nodes/web/controllers")
  261. for _, v in ipairs(files) do
  262. controllerList[v] = require("controllers." .. v)
  263. end
  264. end
  265. -- 热更新
  266. function root:update()
  267. protoUtil:update()
  268. end
  269. -- 处理http请求
  270. function root:http_request(ip, url, method, headers, path, query, body)
  271. log.info(
  272. "http_request ip[%s] url[%s] method[%s] headers[%s] path[%s] query[%s]",
  273. tostring(ip),
  274. tostring(url),
  275. tostring(method),
  276. tostring(headers),
  277. tostring(path),
  278. tostring(query)
  279. )
  280. if method == "POST" and not l_is_match_sign(path, query, body) then
  281. return ERROR()
  282. end
  283. local smethod, name, args, response = l_decode_sproto(ip, headers, path, body)
  284. log.info(
  285. "http_request l_decode_sproto smethod[%s] name[%s] args[%s] response[%s]",
  286. tostring(smethod),
  287. tostring(name),
  288. tostring(args),
  289. tostring(response)
  290. )
  291. smethod = smethod or method
  292. if smethod == "OPTIONS" then
  293. return OPTIONS()
  294. elseif smethod == "GET" then
  295. return GET(path, query)
  296. elseif smethod == "POST" then
  297. return POST(path, body)
  298. elseif smethod == "SPROTO" then
  299. return SPROTO(name, args, response)
  300. else
  301. return ERROR()
  302. end
  303. end
  304. return root