环境配置的生效规则
说了这么多,现在串起来看。运行 init 脚本就会将某一环境的系列文件复制到当前的文件中, 这些文件就是 index.php yii 入口文件和 *-local.php 配置文件。 复制到哪呢?复制到了 /path/to/digpage.com/ 目录下面, 并覆盖 frontend backend console common 中对应的 config 目录和入口脚本 ( index.php 或 yii , common 中没有入口脚本) 。
在初始情况下,即未运行过 init 脚本之前,各应用目录(frontend, beckend, console)和通用目录(common), 都是已经有一些配置文件了。就是config目录下的 bootstrap.php main.php params.php 。
总的讲, *.php 与环境、配置相关的文件都有哪些呢?有表示主配置的 main.php main-local.php , 有表示全局参数的 params.php params-local.php ,表示引导阶段的 bootstrap.php , 有表示入口脚本的 yii 和 index.php 。其中, bootstrap.php 在 别名(Alias) 中有介绍, 且在优先顺序与其他配置文件的原则是一样的,下面就不再重复讲了。
运行了 init 脚本后,环境中的文件也被复制出来。 这些配置文件成套地分布在各应用目录和通用目录的 config 目录下。 而 index.php 入口脚本则分布在各应用目录的 web 目录下, yii 入口脚本则只放在应用根目录下。
入口脚本我们在 入口文件index.php 已经讲了,这里就不讲。剩下的,来看看配置文件们。 其中,所有的 *-local.php 都来自于你选用的环境,表示本地配置的意思。他们不会被写入到代码仓库中。 当然,这些环境,也就是整个 /path/to/digpage.com/environments 目录都会被写入代码仓库。
而所有不带 *-local.php 的main和params配置文件,都不是环境的内容。但在最终的运行环境中,他们是起作用的。
上面讲到的配置文件有很多,有前台、后台、命令行和common的,有带local的、不带local的, 有params、main等,看起来好复杂的样子。那么一个环境发生作用时,这些文件是怎么个顺序呢? 这要看看 入口文件index.php 部分的内容,但总的原则是:
- 前台、后台和命令行的配置文件间,互不干扰,各管各的。没有先后顺序一说。 因为Yii在任意时间,要么是在跑前台,要么是在跑后台。还记得么?他们是不同的应用,他们是独立的。 但是,这里有个common,通用于前台、后台等。common的内容被前台或后台的覆盖。
- local和不带local的。明显的,local的是本地配置文件,不带local的是团队间通用的配置。 因此,local的覆盖不带local的。
- params, main。这2类文件表示的配置内容并不重叠,他们逻辑上不存在谁覆盖谁的问题。 如果看看源代码,可以发现,params只是main配置的一部分。 而main的内容,是作为参数传递给应用的构造函数。 因此,这两者不存在谁覆盖谁的问题。
环境的使用¶
环境在具体使用上,把握这么几个原则:
- 与前后台无关,且与环境无关的配置项,写到 digpage.com\common\config\main.php 中去。 不要写到环境中去,也不要写到前台或后台的配置文件中去。 比如,当使用 FileCache 作为缓存时,这是与环境无关、与前后台无关的, 或者说所有环境下,前后台的配置都相同。 有关配置项要写到 digpage.com\common\config\main.php 中去。
- 无关环境的配置,不要写到环境中去,写到应用的配置中去。 如,应用的ID,无论是开发环境还是产品环境,ID是不会变的。但前后台ID是不同的。 因此,ID的配置项写到 digpage.com\frontend\config\main.php 中去。 而不要写到 digpage.com\environment\frontend\config\main-local.php 中去。
- 与环境有关,但与前后台无关的配置项,要写到环境的 common 配置中去。 比如,有的应用前后台使用的数据库是一致的,因此,其 db 配置项应该是一样的。 但在开发时,所使用的数据库服务与产品时的数据库服务肯定是不一样的。 这种情况下,要所配置项写到 digpage.com\environments\dev\common\main-local.php
- 环境配置文件只提供框架。凡是环境配置文件,对于敏感信息,如,数据库地址、用户名、密码、API Key等信息, 一律留空,供团队成员在调用 init 后自行填写。
- 本地配置绝不提交代码库。因此,所有的应用目录(frontend, backend等,并非environment目录)下的, 所有 *-local.php 都不提交代码库。这点Yii已经通过 .gitignore 为我们做好了。 关于 .gitignore 的有关信息,可以看看 Git文档 的有关内容。
这样做能达到什么效果呢?
- 整个代码仓库中,不会有任何的敏感信息。这个代码仓库即使被外部获取,其危害程度也仅限于代码。 数据库、Web Service 等密码还不至于泄露。
- 增加、删除、更新配置项的所有修改,都可以通过版本控制系统向整个团队分发。
- 所有团队成员只需要记住权限范围内的敏感信息,就可以完成工作。 本地开发的队友,只要有本地的数据库连接信息就可以开发。 负责测试的队友,只需要知道测试数据库服务器连接信息就可进行测试。 负责部署的队友,只需要知道产品数据库的连接信息就可以完成部署。 所有团队成员只需要记住各自权限范围内有限的几个敏感信息就可以了。
不足之处就是每次 pull 代码时,如果配置文件有更新,需要团队成员调用 init 将新的配置文件覆盖本地配置。 然后需要手动填入敏感信息。但这种情况在初期配置不太稳定的情况下,根据团队迭代频率,一般一天一次。 而等开发进入正常阶段后,配置文件相对稳定,极少有需要修改的。
注意 cookieValidationKey
另外还有一个需要读者朋友们留意的地方,就是每次调用 init 脚本切换、更新环境配置时, cookieValidationKey 都会被重新生成的随机串所覆盖。这往往会导致更新前后 cookieValidationKey 不一致。 从安全角度来讲,定时不定时地更新 cookieValidationKey 也是无可厚非的。 但同时我们也要看到由此产生的一个副作用,那就是原先保存在用户机器上的cookie在下次访问时,会全部失效。 一个简单表现就是已经设置了自动登录的用户,在更新 cookieValidationKey 后,全部需要重新登录。
这在大部分情况下,我们认为这是可以接受的。相信大家在使用互联网的过程中,也有遇到过重新登录的情况。 因此,通常我们也可以很放心的使用 init 脚本,而不必特别地去关注自动生成的 cookieValidationKey 。
这种情况下, cookieValidationKey 是一个纯粹的、与本地环境密切相关的配置项,我们不用太操心它。
但是,有的情况下, cookieValidationKey 则不宜由 init 脚本来自动生成,而需要运维人员人工进行干预。
需要人工干预的情况,一般出现在对cookie要求比较严格的场景。 如,当你的应用采用分布式架构提供服务,同时运行在多个节点的时候。 有的负载均衡策略会将同一用户的先后2次请求随机分配给不同的节点进行处理。 而如果这两个节点的 cookieValidationKey 不一致,那么就会出现用户就会收到很奇怪的错误信息。
因此,在分布式情况下,最简便的处理方式还是通过人工干预,确保各节点的 cookieValidationKey 始终一致。
这种情况下, cookieValidationKey 已经不是一个纯粹的本地环境配置项了,最多算是一个环境级别的配置项, 而与本地、本机没有多大关系了。这种情况下, 应当将 cookieValidationKey 与其他诸如数据库密码等敏感信息等同视之,由具有权限的、负责运维的人员掌握。 并在每次调用 init 脚本后,将所掌握的 cookieValidationKey 填写到相应的配置项中去。
这里舍弃掉了init脚本自动生成的 cookieValidationKey 。 更新前后, cookieValidationKey 未发生改变,因此,对于应用的用户而言没什么影响。
幸运的是,绝大多数情况下,我们还无需对于 cookieValidationKey 操太多的心,可以完全由init脚本自动生成。
其实,对于Yii开发团队而言,刚开始的时候,是将 cookieValidationKey 放在非环境配置文件 main.php 中的。 后来,觉得这个配置项与虽然不一定是本地相关的,但起码与环境有关, 因此后来还是放在环境配置文件main-local.php中。
只是,由于安全上的考虑,对于未设置 cookieValidationKey 的情况会抛出异常。 同时,又为了方便开发者,又采用了让 init 脚本生成随机串的方式来自动配置。