巧设 Openresty 包含路径
路径的难题
我在之前的一篇文章中提到,关于 OpenResty 中的文件包含路径,是个值得注意的问题。
OpenResty 仅会将它自己的 lualib
目录加入 package.path
和 package.cpath
,我们的项目目录需要自己处理。
最初我曾经试过将 项目目录加入到 package.path
和 package.cpath
中,确实达到了目的。
但在 nginx 上配置了第二个 server 并将它的目录也加入包含路径之后,由于 lua_code_cache
的存在,不同 server 间的相同相对路径的文件的缓存会互相冲突,导致 require 可能不能加载正确的文件。
巧妙的方案
其实解决方案来自 PHP 中 autoload 的启发,我使用了一些 nginx 配置和一个单独的函数用来加载项目中的文件。
服务器上我的目录结构如下:
如图所示,所有的 server 都放在 /data/app/web
下,由于.
在 lua 包含路径中的特殊含义,使用 OpenResty 的项目目录中的 .
都替换成了 _
。
在 nginx 配置中,我将 /data/app/web
加入到了 package.path
和 package.cpath
。
1 | lua_package_path '/data/app/web/?.lua;;'; |
入口文件代码如下:
1 | --- 定义NULL常量 |
通过利用 lua_package_path
配置对 require
进行封装,我构造了全局的 loadMod
函数用于加载项目中的文件。实际上,下面的代码是等同的:
1 | local model1 = loadMod("core.app") |
通过 lua_package_path
中追加的所有项目的主目录,require
能够加载到正确的文件。
进阶的方案
这个方案看起来已经很好的达到了我们的目标,但是实际使用中,却不是那么方便。
在加载 OpenResty 的自有扩展和库的时候,我们还是必须使用 require
,否则将会因为路径不对找不到文件。比如:
1 | local json = require("cjson") |
看起来好像没什么问题,但是实际编码过程中,不经意写错的时候还是很多的,确实不是很方便。于是,我开始构思一个简易通用的方案。
1 | --- 定义NULL常量 |
现在不管是项目的文件还是自带的扩展和库,都可以使用 loadMod
加载,不需要再去分辨加载的是否是项目自己的文件。
我在三个 server 的入口文件中,都加上了这段代码,但转念一想,使用重复的代码可不是一个好程序猿的习惯。于是,我将上面的代码保存为 init.lua
,使用 init_by_lua_file
来加载。这样,我们将一个文件加载一次,所有项目就都能够使用了。
1 | init_by_lua_file /usr/local/openresty/luainit/init.lua; |
结语
这个最终方案我们的项目正在使用,配置简单,使用起来也很方便,而且经过了2个线上项目的检验,没有发现缺陷。
巧设 Openresty 包含路径