本地开发环境使用https
目前,大多数Web开发工作都在 http://localhost:port
下完成。然而,本地开发使用https有时是必要的,例如向一个https站点传送数据
本文讨论了如何在本地开发环境开启https
https自签名证书
https是http协议+ssl协议,为网络请求中的数据提供了加密保护,减少数据被截获的风险。没有特殊原因的话,生产环境的服务都需要开启https
正常情况下,为部署在生产环境的http服务开启https需要几个条件:
- 服务绑定在域名上,且该域名通过DNS解析到了服务所在主机的ip。如果是国内域名,还需要给域名备案
- 域名绑定了数字证书,该证书来自受信任的证书颁发机构(CA),如Let's Encrypt
- 服务本身支持https功能,已经开启,未被防火墙阻拦
在本地开发环境,localhost
这个域名被系统默认解析到了 127.0.0.1
,我们可以直接用
至于数字证书,mkcert
可以创建只在本地受信任的https自签名证书,非常适合开发测试
WSL下安装 mkcert
并初始化
sudo apt install mkcert
mkcert --install
在 ~/.local/share/mkcert
下的 rootCA.pem
就是mkcert的根证书,它会告诉WSL:以后看到由我 mkcert
生成的证书,就信任它别报警哈
由于Windows和WSL的证书是分开管理的,还需在Windows下导入 mkcert
根证书
win+R
打开运行窗口,输入 certmgr.msc
,打开证书管理器,在受信任的根证书颁发机构-证书上点击右键,所有任务-导入,添加WSL中的 ~/.local/share/mkcert/rootCA.pem
。添加时有警告
前端开启https
如果你使用netx.js搭建前端且版本在 13.5.1
以上,按照官方教程在 packages.json
中增加 dev-https
快捷命令
"dev-https": "next dev --experimental-https",
然后启动
pnpm run dev-https
该步骤会自动调用 mkcert
(如果未安装会自动下载安装),为域名 localhost
创建https证书,保存到 certificates
目录下,并开启https服务
如果你使用其他框架,在前端项目目录下运行
mkcert localhost
这会生成 localhost.pem
证书文件和 localhost-key.pem
证书密钥文件(和next.js框架下 certificates
目录内的一样),然后根据框架文档,一般都需要手动引入这两个文件,然后开启https
假定前端服务在 https://localhost:3000
,如果你还没在Windows导入 mkcert
的根证书,或导入后没重启过浏览器,就会有这样的报警
每一步都完整操作的话,此时Windows的浏览器应该已经可以访问https前端了
后端开启https
如果前端已经开启https,而后端仍是http,前端将无法访问后端的任何接口,这是浏览器同源策略所限制的,即不能从安全源跨域访问不安全源。如果后端开启了https,而前端未开启,从前端仍然可以访问后端——浏览器不会限制从不安全源跨域访问安全源
为了让前后端互相访问,需要也为后端开启https。在后端项目目录下运行 mkcert localhost
为 localhost
域名生成证书
根据后端框架的不同,使证书生效、开启https服务的方式也不同
如果你使用fastapi,首先设置好跨域策略中间件
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins="localhost",
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
allow_origins
可以只写允许跨域访问后端接口的域名 localhost
,或域名+端口 localhost:3000
,或协议+域名+端口 https://localhost:3000
然后在启动后端服务时,指定 --ssl-keyfile
和 --ssl-certfile
uvicorn src.abqus.main:app --reload --ssl-keyfile localhost-key.pem --ssl-certfile localhost.pem
这时,https://localhost:8000
后端服务、https://localhost:3000
前端服务都已经开启,且两者可以互相访问
如果前端或后端框架本身不支持https服务、或配置https比较麻烦,还可以考虑在本地开一个nginx服务器,通过反向代理将https请求传递到http服务
在本地使用localhost以外的域名
如果你不想用 localhost
,想换个域名,就得把自定义的域名解析到 127.0.0.1
本地主机。hosts文件允许我们这样做
WSL的hosts文件在 /etc/hosts
,Windows的hosts文件在 C:\Windows\System32\drivers\etc\hosts
,在这两个文件添加以下内容
127.0.0.1 dev.local
重启浏览器后,自定义的域名解析就完成了
接着还需要配置前端、后端服务,指定域名。不同框架的配置也不同,对于next.js,只需为快捷命令添加 -H
参数。next.js会自动重新为 dev.local
生成自签名证书,文件名还是 localhost.pem
,但内部的编码已经改变
"dev-https": "next dev --experimental-https -H dev.local",
对于fastapi,则需要重新为 dev.local
生成自签名证书,启动服务时指定 host
参数为 dev.local
mkcert dev.local
uvicorn src.abqus.main:app --reload --ssl-keyfile dev.local-key.pem --ssl-certfile dev.local.pem --host dev.local
至此,我们就可以通过 https://dev.local:3000
和 https://dev.local:8000
访问前端和后端
如果你觉得写端口还是太麻烦,希望为前端和后端分配两个域名,比如 dev.front
和 dev.back
,就需要使用nginx等反向代理服务器
不写端口不代表没有端口,而是使用默认端口(https的80和https的443)。一台主机不能在443端口开两个服务,所以只能将 localhost:3000
转发到 dev.front:443
,将 localhost:8000
转发到 dev.back:443
反向代理的配置,本文不再详述
结语
经过以上配置,你应该能在本地使用https开发了。开发环境与生产环境的差别进一步减少,能提前规避很多问题
玩得开心!