webapp.lua 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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 isGmJson, pathData = l_is_match_gm_json(path)
  167. if isGmJson then
  168. path = pathData
  169. body = cjson_decode(body)
  170. end
  171. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  172. local controllerName, method = l_get_math_controller_and_func(path)
  173. local controller = controllerList[controllerName]
  174. if not controller then
  175. log.error("controller[%s] not exist", controllerName)
  176. return l_get_unmatch_controller(res)
  177. end
  178. local func = controller[method]
  179. if not func then
  180. log.error("controller[%s] has no method[%s] ", controllerName, method)
  181. return l_get_unmatch_process(res)
  182. end
  183. local param = controllerName == "sgm" and body or l_get_gm_param(body)
  184. local errCode, ret = func(param)
  185. if isGmJson then
  186. res.body = l_pack_gm_rsp(errCode, ret)
  187. else
  188. res.body = l_pack_rsp(errCode, ret)
  189. end
  190. return res.code, res.body, res.headers
  191. end
  192. local function OPTIONS(body)
  193. local headers = l_get_req_headers()
  194. headers["Content-Type"] = nil
  195. return 200, body, headers
  196. end
  197. local function ERROR()
  198. return 200, l_pack_rsp(code.REQUEST_NOT_FOUND), l_get_req_headers()
  199. end
  200. local function SPROTO(name, args, response)
  201. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  202. local controllerName = _get_cotroller(name)
  203. local controller = controllerList[controllerName]
  204. if not controller then
  205. log.error("SPROTO controller[%s] not exist", controllerName)
  206. res.body = response({code = code.REQUEST_NOT_FOUND})
  207. return res.code, res.body, res.headers
  208. end
  209. local func = controller[name]
  210. if not func then
  211. log.error("SPROTO controller[%s] has no name[%s] ", controllerName, name)
  212. res.body = response({code = code.REQUEST_NOT_FOUND})
  213. return res.code, res.body, res.headers
  214. end
  215. local errCode, resData = func(args)
  216. resData = resData or {}
  217. resData.code = errCode
  218. res.body = response(resData)
  219. return res.code, res.body, res.headers
  220. end
  221. -- 解析请求参数
  222. local function l_decode_sproto(ip, headers, path, body)
  223. if path ~= "/pb" then
  224. return
  225. end
  226. local sz = headers["content-length"] or #body
  227. local ok, pType, pName, args, response = protoUtil:decode_c2s_req(body, sz)
  228. if not ok then
  229. return
  230. end
  231. -- pName = pName:gsub("_", "/")
  232. -- pName = string.format("/%s", pName)
  233. if headers and headers["proxy-client-ip"] then
  234. ip = headers["proxy-client-ip"]
  235. end
  236. args.ip = ip
  237. return "SPROTO", pName, args, response
  238. end
  239. local function l_is_match_sign(path, query, body)
  240. log.info("l_is_match_sign path[%s] query[%s]", tostring(path), tostring(query))
  241. local salt = ""
  242. local sign = query.sign
  243. if path == "/pb" then
  244. salt = GAME_SALT_MD5
  245. elseif path == "/json" then
  246. salt = SALT_MD5
  247. end
  248. log.info("l_is_match_sign salt[%s]", tostring(salt))
  249. if not sign then
  250. return false
  251. end
  252. local genSign = md5.sumhexa(body .. salt)
  253. log.info("l_is_match_sign genSign[%s]", tostring(genSign))
  254. if genSign == sign then
  255. return true
  256. end
  257. return false
  258. end
  259. -- 初始化
  260. function root:init()
  261. local files = lfsUtil:get_path_lua_files("nodes/login/controllers")
  262. for _, v in ipairs(files) do
  263. controllerList[v] = require("controllers." .. v)
  264. end
  265. end
  266. -- 热更新
  267. function root:update()
  268. protoUtil:update()
  269. end
  270. -- 处理http请求
  271. function root:http_request(ip, url, method, headers, path, query, body)
  272. log.info(
  273. "http_request ip[%s] url[%s] method[%s] headers[%s] path[%s] query[%s]",
  274. tostring(ip),
  275. tostring(url),
  276. tostring(method),
  277. tostring(headers),
  278. tostring(path),
  279. tostring(query)
  280. )
  281. if method == "POST" and not l_is_match_sign(path, query, body) then
  282. return ERROR()
  283. end
  284. local smethod, name, args, response = l_decode_sproto(ip, headers, path, body)
  285. log.info(
  286. "http_request l_decode_sproto smethod[%s] name[%s] args[%s] response[%s]",
  287. tostring(smethod),
  288. tostring(name),
  289. tostring(args),
  290. tostring(response)
  291. )
  292. smethod = smethod or method
  293. if smethod == "OPTIONS" then
  294. return OPTIONS()
  295. elseif smethod == "GET" then
  296. return GET(path, query)
  297. elseif smethod == "POST" then
  298. return POST(path, body)
  299. elseif smethod == "SPROTO" then
  300. return SPROTO(name, args, response)
  301. else
  302. return ERROR()
  303. end
  304. end
  305. return root