webapp.lua 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 l_is_match_static(path)
  59. if not IS_TEST then
  60. return false
  61. end
  62. if path == "/" then
  63. path = "/static/index.html"
  64. end
  65. local offset = path:find("/", 2, true)
  66. if not offset then
  67. return false
  68. end
  69. -- 非静态资源
  70. local controller = path:sub(1, offset - 1)
  71. if controller ~= "/static" then
  72. return false
  73. end
  74. -- 读取静态文件
  75. local filename = path:sub(offset + 1)
  76. local content = staticfile[filename]
  77. if content then
  78. return true, 200, content
  79. end
  80. return true, 404, "404 Not found"
  81. end
  82. -- 匹配GM后台
  83. local function l_is_match_gm_json(path)
  84. local offset = path:find("json")
  85. if not offset then
  86. return false
  87. end
  88. return true, "/sgm_interface"
  89. end
  90. local function l_pack_rsp(errCode, resData)
  91. local res = {code = errCode, data = resData}
  92. return cjson_encode(res)
  93. end
  94. local function l_pack_gm_rsp(errCode, resData)
  95. resData = resData or {}
  96. resData.code = errCode or -1
  97. return cjson_encode(resData)
  98. end
  99. -- 请求
  100. local function GET(path, query)
  101. local isStatic, errCode, body = l_is_match_static(path)
  102. if isStatic then
  103. return errCode, body, l_get_req_headers(true)
  104. end
  105. local isGmJson, pathData = l_is_match_gm_json(path)
  106. if isGmJson then
  107. path = pathData
  108. body = body or query.body
  109. local ok, data = pcall(cjson_decode, body)
  110. if not ok then
  111. log.error("get params %s", tostring(body))
  112. body = nil
  113. else
  114. body = data
  115. end
  116. end
  117. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  118. local controllerName, method = l_get_math_controller_and_func(path)
  119. local controller = controllerList[controllerName]
  120. if not controller then
  121. log.error("controller[%s] not exist", controllerName)
  122. return l_get_unmatch_controller(res)
  123. end
  124. local func = controller[method]
  125. if not func then
  126. log.error("controller[%s] has no method[%s] ", controllerName, method)
  127. return l_get_unmatch_process(res)
  128. end
  129. local errCode, ret = func(body or query)
  130. if isGmJson then
  131. res.body = l_pack_gm_rsp(errCode, ret)
  132. else
  133. res.body = l_pack_rsp(errCode, ret)
  134. end
  135. return res.code, res.body, res.headers
  136. end
  137. local function l_get_gm_param(body)
  138. local function split(str, reps)
  139. local res = {}
  140. str:gsub(
  141. "[^" .. reps .. "]+",
  142. function(w)
  143. table.insert(res, w)
  144. end
  145. )
  146. return res
  147. end
  148. local query = {}
  149. for index, value in ipairs(split(body, "&")) do
  150. for k, v in value:gmatch("([^=]+)=([^=]+)") do
  151. query[k] = v
  152. end
  153. end
  154. return query
  155. end
  156. local function POST(path, body, response)
  157. local isStatic, errCode, sbody = l_is_match_static(path)
  158. if isStatic then
  159. return errCode, sbody, l_get_req_headers(true)
  160. end
  161. local isGmJson, pathData = l_is_match_gm_json(path)
  162. if isGmJson then
  163. path = pathData
  164. body = cjson_decode(body)
  165. end
  166. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  167. local controllerName, method = l_get_math_controller_and_func(path)
  168. local controller = controllerList[controllerName]
  169. if not controller then
  170. log.error("controller[%s] not exist", controllerName)
  171. return l_get_unmatch_controller(res)
  172. end
  173. local func = controller[method]
  174. if not func then
  175. log.error("controller[%s] has no method[%s] ", controllerName, method)
  176. return l_get_unmatch_process(res)
  177. end
  178. local param = controllerName == "sgm" and body or l_get_gm_param(body)
  179. local errCode, ret = func(param)
  180. if isGmJson then
  181. res.body = l_pack_gm_rsp(errCode, ret)
  182. else
  183. res.body = l_pack_rsp(errCode, ret)
  184. end
  185. return res.code, res.body, res.headers
  186. end
  187. local function OPTIONS(body)
  188. local headers = l_get_req_headers()
  189. headers["Content-Type"] = nil
  190. return 200, body, headers
  191. end
  192. local function ERROR()
  193. return 200, l_pack_rsp(code.REQUEST_NOT_FOUND), l_get_req_headers()
  194. end
  195. local function SPROTO(name, args, response)
  196. local res = {code = 200, body = nil, headers = l_get_req_headers()}
  197. local controllerName, method = l_get_math_controller_and_func(name)
  198. local controller = controllerList[controllerName]
  199. if not controller then
  200. log.error("SPROTO controller[%s] not exist", controllerName)
  201. res.body = response({code = code.REQUEST_NOT_FOUND})
  202. return res.code, res.body, res.headers
  203. end
  204. local func = controller[name]
  205. if not func then
  206. log.error("SPROTO controller[%s] has no name[%s] ", controllerName, name)
  207. res.body = response({code = code.REQUEST_NOT_FOUND})
  208. return res.code, res.body, res.headers
  209. end
  210. local errCode, resData = func(args)
  211. resData = resData or {}
  212. resData.code = errCode
  213. res.body = response(resData)
  214. return res.code, res.body, res.headers
  215. end
  216. -- 解析请求参数
  217. local function l_decode_sproto(ip, headers, path, body)
  218. if path ~= "/pb" then
  219. return
  220. end
  221. local sz = headers["content-length"] or #body
  222. local ok, pType, pName, args, response = protoUtil:decode_c2s_req(body, sz)
  223. if not ok then
  224. return
  225. end
  226. -- pName = pName:gsub("_", "/")
  227. -- pName = string.format("/%s", pName)
  228. if headers and headers["proxy-client-ip"] then
  229. ip = headers["proxy-client-ip"]
  230. end
  231. args.ip = ip
  232. return "SPROTO", pName, args, response
  233. end
  234. local function l_is_match_sign(path, query, body)
  235. log.info("l_is_match_sign path[%s] query[%s]", tostring(path), tostring(query))
  236. local salt = ""
  237. local sign = query.sign
  238. if path == "/pb" then
  239. salt = GAME_SALT_MD5
  240. elseif path == "/json" then
  241. salt = SALT_MD5
  242. end
  243. log.info("l_is_match_sign salt[%s]", tostring(salt))
  244. if not sign then
  245. return false
  246. end
  247. local genSign = md5.sumhexa(body .. salt)
  248. log.info("l_is_match_sign genSign[%s]", tostring(genSign))
  249. if genSign == sign then
  250. return true
  251. end
  252. return false
  253. end
  254. -- 初始化
  255. function root:init()
  256. local files = lfsUtil:get_path_lua_files("../nodes/web/controllers")
  257. for _, v in ipairs(files) do
  258. controllerList[v] = require("controllers." .. v)
  259. end
  260. end
  261. -- 热更新
  262. function root:update()
  263. protoUtil:update()
  264. end
  265. -- 处理http请求
  266. function root:http_request(ip, url, method, headers, path, query, body)
  267. log.info(
  268. "http_request ip[%s] url[%s] method[%s] headers[%s] path[%s] query[%s]",
  269. tostring(ip),
  270. tostring(url),
  271. tostring(method),
  272. tostring(headers),
  273. tostring(path),
  274. tostring(query)
  275. )
  276. if method == "POST" and not l_is_match_sign(path, query, body) then
  277. return ERROR()
  278. end
  279. local smethod, name, args, response = l_decode_sproto(ip, headers, path, body)
  280. log.info(
  281. "http_request l_decode_sproto smethod[%s] name[%s] args[%s] response[%s]",
  282. tostring(smethod),
  283. tostring(name),
  284. tostring(args),
  285. tostring(response)
  286. )
  287. smethod = smethod or method
  288. if smethod == "OPTIONS" then
  289. return OPTIONS()
  290. elseif smethod == "GET" then
  291. return GET(path, query)
  292. elseif smethod == "POST" then
  293. return POST(path, body)
  294. elseif smethod == "SPROTO" then
  295. return SPROTO(name, args, response)
  296. else
  297. return ERROR()
  298. end
  299. end
  300. return root