用 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

这是怎么回事,难道哪里设置有误?

我网上查了下资料,其中说到:

  1. 上游服务器故障:当 Nginx 作为代理服务器时,它将请求转发给上游服务器处理,并将上游服 …
  2. 连接超时:如果 Nginx 在与上游服务器建立连接时遇到超时问题,它将无法获取响应并返回 "502 Bad Gateway" 错误。这可能是由于上游服务器响应时间过长、网络连接问题或 Nginx 配置中的超时设置不足引起的
  3. 错误的代理配置:Nginx 作为代理服务器时,需要正确配置代理规则和请求头信息,以便将请 …
  4. 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!

接下来,大东 在此基础上做了个稍微有点复杂的动态网站,在此之前,他对动态网站的后端和前端技术都不熟悉,让我感叹年轻人学东西就是快

相关内容


独立思考最难得,赞赏支持是美德!(微信扫描下图)