用 Nim 编程语言做一个最简单的动态网站
2024-08-25 乙酉 甲辰年 壬申 辛酉 - 晴
作者:海云青飞
静态网站和动态网站的区别
在今天之前,海云青飞 从未做过动态网站。问题来了,什么是动态网站,静态网站又是什么意思
-
静态网站
目前的 海云青飞 官方网站 https://www.tuenhai.com,你打开任意一个页面,你都无法与它动态交互,这就是静态网站
-
动态网站
动态网站,用户可以和网站交互,如提交表单,在论坛发表言论等等
使用动态网站的好处
海云青飞 不是专业程序员,不过也写过一些小的单机软件,如果我想要让别人使用,我就要手动发送它,或者放到某个网站上让别人手动下载,这就比较烦琐、低效
如果把单机软件做成动态网站,为别人提供类似功能的服务,别人就省去了下载软件的步骤,并且世界各地的人们都随时可以使用
我虽然早知道做动态网站的好处,只是本人非程序员职业,一直懒得去研究其中的细节。然而,知者不难,难者不知,其实,做个最简单的动态网站是非常容易的,今天我第一次尝试就成功了,下面说说步骤
做动态网站的第一步,域名 DNS 设置
首先准备好做动态网站的域名,我用的是子域名,类似 good.tuenhai.com
-
在域名控制面板,把 A 记录绑定到
good.tuenhai.com
意思是,域名
good.tuenhai.com
绑定一个 IPv4 地址 -
在域名控制面板,把 AAAA 记录绑定到
good.tuenhai.com
意思是,域名
good.tuenhai.com
绑定一个 IPv6 地址。如果没有 IPv6 地址,则此步可略过
做动态网站的第二步,Nginx 设置端口转发
做动态网站的核心就是,自己编写一个软件,以在服务器上对外提供服务,这有二个前提:
-
域名要有独立 IP,这样别人才可以茫茫网络海洋上找到
good.tuenhai.com
-
软件要对外监听特定的端口,接收信息并作出反馈
HTTP 服务的端口分二种:
- 443 端口,此端口传输的信息都经过加密,外界无从知道传输的内容
- 80 端口,此端口用明文传输信息。有的国家对人民不放心,会监视经过 80 端口传输的信息,你看过什么文章,发送过什么消息,它们知道得一清二楚,即使你不在乎这点,你在网上使用的用户名、密码也可能会被它们截获
https://
开头的网址都是加密传输信息的http://
开头的网址都是明文传输信息的聪明人的做法是,从不打开
http://
开头的网址我们的服务端软件虽然可以自己直接对外监听 443、80 端口,但是我们一般不这么做,因为这样的话在技术上很多细节要自己处理
那么应该怎么做呢?让 Nginx 站在前台提供基础服务,并让 Nginx 把信息转发到同机的特定端口,而我们的软件就在监听这个端口,它接收到 Nginx 传过来的信息后再通过这个端口向 Nginx 反馈信息,Nginx 再把接收到的信息原封不动传输给网站的用户
下面是 Nginx 设置端口转发(也叫反向代理)的示例:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name good.tuenhai.com;
ssl_certificate /etc/letsencrypt/live/tuenhai.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/tuenhai.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
root /home/tuenhai.com/good;
# index index.html index.htm;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
proxy_pass http://127.0.0.1:3210;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
上面示例中 proxy_pass http://127.0.0.1:3210;
就是让 Nginx 把从外界接收到信息转发到本机端口 3210
例子中,指定 https 证书的几行是我从域名 tuenhai.com
的 Nginx 配置文件中直接复制过来的,并没有运行 certbot 申请新的证书
运行下面命令让 Nginx 使用新的设置:
sudo nginx -s reload
关于 Nginx 502 Bad Gateway
我打开页面 https://good.tuenhai.com
,页面显示:
502 Bad Gateway
这是怎么回事,难道哪里设置有误?
我网上查了下资料,其中说到:
- 上游服务器故障:当 Nginx 作为代理服务器时,它将请求转发给上游服务器处理,并将上游服 …
- 连接超时:如果 Nginx 在与上游服务器建立连接时遇到超时问题,它将无法获取响应并返回 "502 Bad Gateway" 错误。这可能是由于上游服务器响应时间过长、网络连接问题或 Nginx 配置中的超时设置不足引起的
- 错误的代理配置:Nginx 作为代理服务器时,需要正确配置代理规则和请求头信息,以便将请 …
- DNS 解析问题:如果 Nginx 配置中使用了上游服务器的主机名,而 DNS 解析无法将主机名解析为正确的 IP 地址,那么 Nginx 将无法连接到上游服务器,从而导致 "502 Bad Gateway" 错误
我意识到,原因在于我的服务端软件目前还不存在,因此不能对 Nginx 转发过来的信息作出响应
接下来我要考虑的问题是,用 Nim 的哪个 Web framework 编写服务端软件
做动态网站的第三步,选择 Nim web framework(HTTP server)
我选择的是 Mummy,这是适用于 Nim 的 HTTP 和 WebSocket 服务器,回归古老的线程方式
为什么使用 Mummy 而不是 async?
-
不再需要使用
{.async.}
、Future[]
、await
等处理函数有颜色的问题 -
保持了多路复用非阻塞套接字 IO 的出色吞吐量
-
不用担心一个阻塞或昂贵的调用会阻塞整个服务器
-
异步会在一些令人惊讶的地方阻塞,比如 DNS 解析和文件读取,这将阻塞所有请求处理
-
编写请求处理程序更简单。阻塞线程完全可以!需要进行 Postgres 查询?没问题,只需等待结果即可
-
编写简单代码比理论上快但可能复杂且容易出错的代码有很大优势
-
调试更简单。异步堆栈跟踪巨大且令人困惑
-
更容易处理错误,只需像平常一样使用
try except
。Mummy 处理程序中未捕获的异常也不会导致整个服务器崩溃 -
Mummy 处理线程和调度,因此您的处理程序可能根本不需要考虑线程
-
利用了多核心和 Nim 团队在 ARC / ORC 和 Nim 2.0 上的出色工作
做动态网站的第四步,编写、运行第一个 Nim 服务端程序
我从 VS Code 登录服务器,先安装 mummy:
nimble install mummy
然后创建文件 server.nim
,代码如下:
import mummy, mummy/routers
proc indexHandler(request: Request) =
var headers: HttpHeaders
headers["Content-Type"] = "text/plain"
request.respond(200, headers, "Hello, good.tuenhai.com!")
var router: Router
router.get("/", indexHandler)
let server = newServer(router)
echo "Serving on http://localhost:3210"
server.serve(Port(3210))
注意,上面代码中指定的通讯端口 3210
,和 Nignx 配置文件中指定的通讯端口相同
然后编译和运行我的第一个 Nim 服务端程序:
nim c --threads:on --mm:orc -r ./server.nim
接着打开浏览器,刷新页面 https://good.tuenhai.com
原来显示的 “502 Bad Gateway” 消失了,取而代之的是:
Hello, good.tuenhai.com!
接下来,大东 在此基础上做了个稍微有点复杂的动态网站,在此之前,他对动态网站的后端和前端技术都不熟悉,让我感叹年轻人学东西就是快
相关内容
- https://github.com/guzba/mummy
- https://github.com/ThomasTJdev/nim_websitecreator/blob/master/devops/config_nginx_default.cfg
独立思考最难得,赞赏支持是美德!(微信扫描下图)