前言
一个前端开发如何摆脱 PHP 去构建后台服务
目标
- 使用 JS 作为语言
- 支持 GET/Post
- 支持指定路由
- 支持 HTTPS
- 支持服务持续运行
环境要求
- Linux 服务器一台
- 确保有 NodeJs 环境
- Linux 已支持 HTTPS 访问(有证书)
创建工程
Step 1:初始化一个 NodeJs 工程后,安装 express 模块
1 | mkdir MyServer |
Step 2:创建 index.js,实现基础的 post/get,实现 HTTPS 功能,以及指定路由
1 | import express from 'express'; |
注意事项:
关于端口指定,除了在代码中指定,还需要到云服务器配置里面打开。详见腾讯云的教程链接。该例子中,来源设置为
0.0.0.0/0
,协议端口设置为TCP:3333
,注意端口最好在 3306-20000 范围内,避免与周知端口冲突。注意代码中 listen 的时候只需要指定 port 即可,host 可不填,默认是 0.0.0.0,代表本机所有 IPv4 的地址均可
NodeJs 指定路由比较麻烦,使用 express 就是为了轻松配置,该例子中,可向
https://x.x.x.x:3333/test/get
发送 GET 请求,Post 同理关于 HTTPS 的配置
HTTPS 的关键就在于代码中三个文件的路径配置,这里不讨论如何配置 HTTPS 证书,但需要了解的是,这三个证书是申请 HTTPS 域名的时候服务商会提供的,配置的时候只需要把服务器里面证书的文件路径替换为自己的即可。
本例子是使用腾讯云,有
apache.key
、apache.crt
和server-chain.crt
这三个文件,不用纠结后缀名,本质都是 txt其中最关键的是
server-chain.crt
这个中级证书,详见下面如何本地调试?
将例子中的 DEV 改为 true,本地执行
node index.js
,即可使用本地调试
Step 3:后台保活
默认情况下,NodeJs 起的服务会卡住当前的终端窗口,当我们关闭窗口或者断开服务器 ssh 连接时,该服务会同时中断。另外 NodeJs 服务如果代码逻辑抛出错误了,也可能会中断。为了实现以下两个目标,我们可以使用 pm2 来进行后台保活
- 即使断开当前的终端链接也不会影响 NodeJs 服务
- 即使 NodeJs 服务挂了能自动重启
安装 pm2
1 | npm install -g pm2 |
启动服务
1 | pm2 start index.js |
终止服务
1 | pm2 stop index.js |
这样即可实现 NodeJs 服务稳定运行
附录:HTTPS 配置的坑
配置 HTTPS 时有一个大坑,网上很多教程都忽略了 credentials 中的 ca 配置,如果缺少了 ca,即缺少了 server-chain.crt 这个证书,会导致从浏览器访问网站(比如 https://x.x.x.x:3333/test/get
)是正常且安全的,即使用 Chrome 地址栏左侧的检测也都是安全的,使用 Postman 工具去模拟请求也是正常回包的。但是从 Android App 访问该请求,App 却会提示 Network request failed
,经过断点,底层抛出的错误是 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found
经过调研,根本原因就是服务器的 HTTPS 配置缺少中级证书。
什么是中级证书
什么是中级证书?需要先了解下 HTTPS 证书链的信任:根证书 -> 中级证书 -> 服务器
- 根证书:受权威机构信任,已经在用户设备中存储;
- 中级证书:由根证书签名而得到信任,负责给下一级的证书签名;
- 服务器证书:由中级证书签名而得到信任
为什么会有中级证书?原因是根证书太宝贵了,而颁发证书的风险太大。于是根证书颁发了很多中级证书,即 CA (证书颁发机构)用自己的私钥进行签名,使中级证书可信任。CA 有了中级证书之后,以后就都用中级证书自己的私钥来签名并颁发给最终用户 SSL 证书(即服务端配置的证书)。当安全事件发生时,不需要撤销根证书,只需撤销中级证书,就可以使从该中级证书发出的证书组不受信任。
如何获取缺失的中级证书
一般来说,无论有多少中级证书,服务商都会全部给你。但假如中级证书丢失了,该如何获取?以下是常用的命令
使用 openssl 查看服务器的证书详细情况,并保存在 log.txt
1 | openssl s_client -connect YourDomain:YourPort -servername YourDomain:YourPort | tee log.txt |
此时如果有中级证书的问题,日志里面会出现下面的错误
1 | verify error:num=20:unable to get local issuer certificate |
从日志中提取证书 url,复制里面出现的 http 地址
1 | openssl x509 -in log.txt -noout -text | grep -i "issuer" |
下载证书
1 | curl --output intermediate.crt 刚提取的地址 |
转成 .pem 文件
1 | openssl x509 -inform DER -in intermediate.crt -out intermediate.pem -text |
其他注意点
值得注意的是,假如 Android 访问成功一次后,再把 ca 配置下掉,也依然能正常访问,推测是设备会缓存已信任过的中级证书。所以真正判断 HTTPS 地址是否生效的标准依然是上述的 openssl 命令
另外,中级证书可能是 0 个也可能是多个,所以 ca 是可选的,类型是一个数组
常用命令
关闭 NodeJS 服务进程
假如 NodeJS 服务的端口为 3333
1 | sudo lsof -i :3333 # 找到 pid |
pm2 启动
1 | pm2 start index.js --watch # 实时监控 js 的方式启动,当 js 文件有变动时,pm2 会自动 reload |
pm2 查看进程
1 | pm2 list # 启动的所有的应用程序 |
pm2 查看日志
1 | pm2 logs # 显示所有应用程序的日志 |
pm2 开启自启动
1 | pm2 start index.js # 先启动你需要的服务 |