参考请注意: 该文档创建于 2022/3/29,请注意随时间流逝文档信息是否过时,是否还有可参考的价值。 该文档仅作为个人笔记记录。 该文档记录时,使用的软件等版本会列在文档中,请注意识别。

让它跑起来

后端的项目配置成本不是一般的高。

这里,我们的目标是,不但让这个项目能够跑起来,然后能够正常开发,测试,debug。
而且也要配置好数据库的访问。

docker

首先学习了一下docker的基本使用,然后按照文档,做了必要的操作,然后通过 docker compose 进行了生产环境部署,效果都很不错。
此外,开发环境它是只跑了 mongodb 和 redis,本地在自己的电脑上跑。但实际上我搞了一个部署在 docker 上的跑法。

package.json

该项目 egg 的 ts-helper 不起作用。
将 package.json 插入以下内容即可:

  1. "egg": {
  2. "declarations": true
  3. },

数据库

mongodb

该项目原本使用 3.2 版本的 mongodb,可以跑。
但是使用 vscode 或 Mongo compass 连接时,会报错,提示需要 mongodb 3.6 以上版本才支持当前的 nodejs driver。

reports maximum wire version 4, but this version of the Node.js Driver requires at least 6 (MongoDB 3.6)

这样,该项目需要 3.6 以上的 mongodb,才能用 vscode 插件等方式连接数据库进行操作。而且 3.2 版本已经是处于 EOL 阶段了。
所以这里选择升级一个新的 mongodb 版本,我这里选择的版本是 5.0。尽量跑之前先升级。理由如下:

如果有了数据之后再去做数据库版本升级,非专业人士不敢做这个数据迁移。这个改动很大(生产环境中),容易出现升级之后数据库没法运行的情况。

redis

项目用 redis 干了这些事:

  • rss 缓存,5 分钟
  • top100 排行榜信息缓存,1 分钟
  • 所有用户尚未回复的帖子缓存,1 分钟
  • 访问论坛页的内容缓存,查询为键,1 分钟
  • 统计一个用户一天发的话题数(并限制数量)
  • 统计一个ip一天注册的用户数(并限制数量)

该项目原本使用 3.2 版本的 redis。

测试/使用环境数据库分离

有这些思路:

  1. 实际使用开发/测试使用一个容器,docker的初始化脚本连续建两个数据库和用户

    1. redis
      redis在一个进程中,通过切换整数型的index来用不同的数据库。
      launch.json里面修改EGG_REDIS_DB环境变量为 1 就 ok 了
    2. mongodb
      这个时候,不能使用原来的init.js创建了,而是另写一个sh文件init-mongodb.sh
      1. mongo admin -u ${MONGO_INITDB_ROOT_USERNAME} -p ${MONGO_INITDB_ROOT_PASSWORD} << EOF
      2. # 切换到 测试数据库,并创建用户
      3. use ${MONGO_INITDB_DATABASE}_test
      4. db.createUser({ user: '${MONGO_INITDB_DATABASE}_test', pwd: '${MONGO_INITDB_DATABASE}_password_test', roles: [{ role: 'readWrite',db: '${MONGO_INITDB_DATABASE}_test' }] })
      5. db.${MONGO_INITDB_DATABASE}.insert({ ${MONGO_INITDB_DATABASE}: 'egg-cnode' })
      6. # 切换到 开发数据库,并创建用户
      7. use ${MONGO_INITDB_DATABASE}
      8. db.createUser({ user: '${MONGO_INITDB_DATABASE}', pwd: '${MONGO_INITDB_DATABASE}_password', roles: [{ role: 'readWrite', db: '${MONGO_INITDB_DATABASE}' }] })
      9. db.${MONGO_INITDB_DATABASE}.insert({ ${MONGO_INITDB_DATABASE}: 'egg-cnode' })
      10. EOF
      另附在这里执行printenv的结果:
      1. mongo-trial-mongodb-1 | HOSTNAME=e5d000827a01
      2. mongo-trial-mongodb-1 | MONGO_INITDB_DATABASE=egg_cnode
      3. mongo-trial-mongodb-1 | PWD=/
      4. mongo-trial-mongodb-1 | MONGO_INITDB_ROOT_PASSWORD=root_password
      5. mongo-trial-mongodb-1 | MONGO_INITDB_ROOT_USERNAME=root
      6. mongo-trial-mongodb-1 | HOME=/home/mongodb
      7. mongo-trial-mongodb-1 | MONGO_PACKAGE=mongodb-org
      8. mongo-trial-mongodb-1 | JSYAML_VERSION=3.13.1
      9. mongo-trial-mongodb-1 | GOSU_VERSION=1.12
      10. mongo-trial-mongodb-1 | MONGO_REPO=repo.mongodb.org
      11. mongo-trial-mongodb-1 | MONGO_VERSION=5.0.5
      12. mongo-trial-mongodb-1 | MONGO_MAJOR=5.0
      13. mongo-trial-mongodb-1 | SHLVL=1
      14. mongo-trial-mongodb-1 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
      15. mongo-trial-mongodb-1 | _=/usr/bin/printenv
      注:会写这个真得好好入门 shell
  2. 开发/测试使用同一镜像但不是同一容器,配备不同的数据卷

这个好办。写一个docker-compose.test.yml,将数据卷名字加_test就可

vscode launch.json

主要问题是带环境变量运行,需要在 vscode launch.json 中配置,不然直接写命令太长
这里就三种配置,egg默认给的:

  • 本地运行+断点调试
  • 单元测试
  • 挂远程调试
    1. {
    2. // 使用 IntelliSense 了解相关属性。
    3. // 悬停以查看现有属性的描述。
    4. // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    5. "version": "0.2.0",
    6. "configurations": [
    7. {
    8. "type": "node",
    9. "request": "launch",
    10. "name": "Egg Debug",
    11. "runtimeExecutable": "npm",
    12. "runtimeArgs": [
    13. "run",
    14. "debug",
    15. "--",
    16. "--inspect-brk"
    17. ],
    18. "env": {
    19. "EGG_REDIS_DB": "0",
    20. "EGG_REDIS_HOST": "localhost",
    21. "EGG_REDIS_PORT": "6379",
    22. "EGG_REDIS_PASSWORD": "your_redis_password",
    23. "EGG_MONGODB_URL": "mongodb://egg_cnode:egg_cnode_password@localhost:27017/egg_cnode",
    24. "EGG_PASSPORT_GITHUB_CLIENT_ID": "your_github_client_id",
    25. "EGG_PASSPORT_GITHUB_CLIENT_SECRET": "your_github_client_secret"
    26. },
    27. "console": "integratedTerminal",
    28. "restart": true,
    29. "protocol": "auto",
    30. "port": 9229,
    31. "autoAttachChildProcesses": true
    32. },
    33. {
    34. "type": "node",
    35. "request": "launch",
    36. "name": "Egg Test",
    37. "runtimeExecutable": "npm",
    38. "runtimeArgs": [
    39. "run",
    40. "test-local",
    41. "--",
    42. "--inspect-brk"
    43. ],
    44. "env": {
    45. "EGG_REDIS_DB": "1",
    46. "EGG_REDIS_HOST": "localhost",
    47. "EGG_REDIS_PORT": "6379",
    48. "EGG_REDIS_PASSWORD": "your_redis_password",
    49. "EGG_MONGODB_URL": "mongodb://egg_cnode_test:egg_cnode_password_test@localhost:27017/egg_cnode_test",
    50. "EGG_PASSPORT_GITHUB_CLIENT_ID": "your_github_client_id",
    51. "EGG_PASSPORT_GITHUB_CLIENT_SECRET": "your_github_client_secret"
    52. },
    53. "console": "integratedTerminal",
    54. "protocol": "auto",
    55. "port": 9229,
    56. "autoAttachChildProcesses": true
    57. },
    58. {
    59. "type": "node",
    60. "request": "attach",
    61. "name": "Egg Attach to remote",
    62. "localRoot": "${workspaceRoot}",
    63. "remoteRoot": "/usr/src/app",
    64. "address": "localhost",
    65. "env": {
    66. "EGG_REDIS_DB": "0",
    67. "EGG_REDIS_HOST": "localhost",
    68. "EGG_REDIS_PORT": "6379",
    69. "EGG_REDIS_PASSWORD": "your_redis_password",
    70. "EGG_MONGODB_URL": "mongodb://egg_cnode:egg_cnode_password@localhost:27017/egg_cnode",
    71. "EGG_PASSPORT_GITHUB_CLIENT_ID": "your_github_client_id",
    72. "EGG_PASSPORT_GITHUB_CLIENT_SECRET": "your_github_client_secret"
    73. },
    74. "protocol": "auto",
    75. "port": 9999
    76. }
    77. ]
    78. }
    注意:
  1. 三个启动配置很多环境变量都是一样的,有的别处也写到了。但麻烦的是“改一处而动全身”。建议这类修改直接左边全部替换。

    登录认证

    支持两种注册登录方式:

  2. 邮箱注册登录

  3. GitHub OAuth 认证

下面我们将这两种方式给调通:

邮箱注册登录

邮箱注册登录还是很麻烦的。

  1. 首先,从自己的邮箱中申请 SMTP 服务,保存好你自己的邮箱授权码,在config.default.js中填入:

image.png
注:host 你用啥邮箱就写啥邮箱对应的 smtp 服务器地址,
port 默认 465,没加密就是 25

  1. controller/sign.js77 行处反注释,打开发邮件开关:

image.png
下面 150 行处还有一个重置密码的邮件开关,改一下:
image.png

  1. 修改config.default.js中的config.host改成你的 socket
  2. debug 模式下会被代码截胡不发。把service/mail.js这里注了:
    image.png

    github oauth 认证

    这个还是很简单的,你在GitHub上面申请一个 oauth,配置如下:
    image.png
    注意的问题:

  3. clientid 和 Client secrets 保存好

  4. 在 dev 端测试,URL的 socket 改成自己的,上线时改成你的域名!
    而且注意,callback URL 后面的路径不能错了。
  5. 修改config.default.js中的config.host改成你的 socket

然后,启动 app,应该就可以正常使用了!
但是这样还没完,以下还有一些地方需要改:

  1. sign.test.js里面should GET /passport/github中的 github 回调页面的正则表达式

    数据模型

业务逻辑

业务逻辑修改

首先目前注册登录有问题:

  1. 如果你的激活邮件没有到,那你的账户邮箱就无法登录,也无法重新注册,登录失败还不给错误提示。
  2. 邮箱和 github 难以绑定。你用邮箱注册了,再用 github 登录,会报错。
  3. github 用户登录,拿到的邮箱是在 github 里设置的公有邮箱,没设置的的可能米有邮箱。

所以这里得改:

  1. 如果激活邮件没到,但是登录,会返回到激活界面重新发激活
  2. 认为 github 等只是一个登录方式,你只要有这个登录方式就可以登录,不必担心多种方式登录时,邮箱等相关信息重合的问题(这种开发者社区又不是游戏,不用担心多平台同一人开小号问题)

首先想一下这个重新激活的问题(可以就这个议题和产品经理吵一架):

假设用户注册的时候需要点击注册邮件来确认激活,才能拥有作为一个注册用户的权利。 那么,假设,用户注册完的时候,服务器发的邮件接收不到,而且重发邮件的页面也关了。 用户需要怎样重新拿到这个激活邮件? 注册的时候肯定是不行的(再次重注册会用户名重复) 所以想让它登录的时候当作未注册用户登录进去,然后返回去立刻重新发送激活验证邮件。 但是经过再次讨论,认为重新发的时候需要重新验证一下之前注册的邮箱。 (涉及到如果)

单元测试

用户逻辑修改了,之前的单元测试是不可能跑通的,需要重新改单元测试。
目前的单元测试的问题:

  1. 很多测试中 mock 的 user 都是不带active的/修改了 active 测试后没改回来,新的 userRequired 中间件要求必须激活才有用户权限。

这个我去查了很多 controller 的单元测试,它们还都是一个it去mock一个用户且很多都是一样的。
加active还必须右侧大文本查找替换