15. 從零開始編寫一個類nginx工具, 如果將nginx.conf轉成yaml,toml,json會怎麼樣

2023-10-20 09:00:26

wmproxy

wmproxy將用Rust實現http/https代理, socks5代理, 反向代理, 靜態檔案伺服器,後續將實現websocket代理, 內外網穿透等, 會將實現過程分享出來, 感興趣的可以一起造個輪子法

專案 ++wmproxy++

gite: https://gitee.com/tickbh/wmproxy

github: https://github.com/tickbh/wmproxy

瞭解三種格式

Json

  • JSON是一種輕量級的資料交換格式,被廣泛使用在Web應用程式之間傳輸資料。
  • JSON使用大括號{}來表示資料結構,使用冒號:來連線鍵和值。
  • JSON支援字串、數位、布林值、null、陣列和物件等多種資料型別。
  • JSON檔案通常用於資料交換、儲存等場景,也可以用作組態檔。
    JSON簡單易讀儲存通用,但JSON原生不支援註釋用來做組態檔比較硬傷。

它流行度極高,基本上每個程式設計師都和他打過交道。
多層級時,對齊和縮排不好控制,容易出錯

Yaml

  • YAML被設計為一種可讀性極強的資料序列化標準,可以用來表達層次化資料。
  • YAML使用空格縮排來表示資料層次結構。
  • YAML支援浮點數、布林值、字串、陣列、對映等多種資料型別。
  • YAML檔案通常用於組態檔、資料交換等場景。

與JSON及TOML相比,結構比較緊湊
但相對用空格縮近,編寫及拷貝時出錯的機率比JSON及TOML高許多

Toml

TOML 旨在成為一個語意明顯且易於閱讀的最小化組態檔格式。
TOML 應該能很容易地被解析成各種語言中的資料結構。

  • TOML是一種簡潔明瞭的鍵值對格式,被設計成可以很容易地對映為雜湊表。
  • TOML使用等號(=)來連線鍵和值,使用縮排來表示資料層次結構。
  • TOML支援整數、浮點數、字串、布林值、陣列、字典等多種資料型別。
  • TOML檔案通常用於組態檔、資料交換等場景。

易於閱讀和編寫語法靈活
與JSON設定相比,TOML在簡潔性方面遠遠勝出;
與YAML設定相比,TOML在簡潔性以及語法靈活性方面遠遠勝出。

三種格式測試資料的對比

我們用Rust的專案組態檔來做對比,為了展示所有的型別,格式有所變更。它以Toml來做組態檔,我們首先先展示toml的格式

內容包含建立者,建立時間,專案名稱,專案依賴等資訊,如果我們將其轉化成可設定的JSON格式時

toml

create="tickbh"
create_time=2023-09-08T10:30:00Z
[project]
# 專案名稱
name="wmproxy"
version="1.1"
editor=2022
# 專案依賴
[project.dependencies]
wenmeng={version = "0.1.21", default-features = false, features = ["std", "tokio"]}
webparse={version = "0.1", default-features = false}

行數12行,註釋兩行,全部頂格開頭,原生支援時間格式

json

{
  "create": "tickbh",
  "create_time": "2023-09-08T10:30:00.000Z",
  "project": {
    "name": "wmproxy",
    "version": "1.1",
    "editor": 2022,
    "dependencies": {
      "wenmeng": {
        "version": "0.1.21",
        "default-features": false,
        "features": [
          "std",
          "tokio"
        ]
      },
      "webparse": {
        "version": "0.1",
        "default-features": false
      }
    }
  }
}

行數23行,層次的遞進比較多,不容易對齊,無法註釋,不支援時間格式

yaml

create: tickbh
create_time: 2023-09-08T10:30:00.000Z
project:
  # 專案名稱
  name: wmproxy
  version: "1.1"
  editor: 2022
  # 專案依賴
  dependencies:
    wenmeng:
      version: 0.1.21
      default-features: false
      features:
        - std
        - tokio
    webparse:
      version: "0.1"
      default-features: false

行數18行,註釋兩行,原生支援時間格式,到features這級行,深度相對較高,但是一眼看上去比json清晰

相對來說JSON比較不適合做比較複雜的組態檔,但VSCODE使用的拓展的JSON以支援註釋功能。

接下來嘗試將nginx.conf格式做轉換

以下嘗試的將

http {
    gzip on;
    server {
        listen 80;  #監聽80的伺服器埠
        server_name wm-proxy.com;  #監聽的域名
       
        location /products {
            proxy_pass http://127.0.0.1:8090/proxy;
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Origin' '*';
        }
        
        location / {
            root wmproxy;
            index index.html index.htm;
        }
    }
}

我們也模仿類似的結構,但是對於toml,yaml,json來說,都沒有一個key兩個值的,要麼我們只能用對應的陣列,此時我來先來初步重構類似的結構。以下我們以toml結構為例,我們分析table的級數有三級,最外層為http,中間層為server為陣列,最內層為location也為陣列,headers我們用之前提到過的mappings,用proxy開頭來表示重寫Reqeust,其它的來表示重寫Response,檔案系統我們用上節提到的file_server
我們先定義http的table,他只有一個屬性gzip為on

[http]
gzip="on"

其次server為一個陣列,那麼我們可以如下定義,有繫結地址和server_name

[[http.server]]
bind_addr="127.0.0.1:80"
server_name="wm-proxy.com"

再然後location也為一個陣列,定義如下

[[http.server.location]]
rule = "/products"
reverse_proxy = "http://127.0.0.1:8090/proxy"
headers = [
  ["+", "Access-Control-Allow-Credentials", "true"],
  ["+", "Access-Control-Allow-Origin", "*"]
]
[[http.server.location]]
rule = "/"
file_server = { root="wmproxy", browse = true, index=["index.html", "index.htm"] }

那麼,最終的結構為如下:

[http]
gzip="on"
[[http.server]]
bind_addr="127.0.0.1:80"
server_name="wm-proxy.com"
[[http.server.location]]
rule = "/products"
reverse_proxy = "http://127.0.0.1:8090/proxy"
headers = [
  ["+", "Access-Control-Allow-Credentials", "true"],
  ["+", "Access-Control-Allow-Origin", "*"]
]
[[http.server.location]]
rule = "/"
file_server = { root="wmproxy", browse = true, index=["index.html", "index.htm"] }

而yaml的格式結構如下:

http:
  gzip: on
  server:
    - bind_addr: 127.0.0.1:80
      server_name: wm-proxy.com
      location:
        - rule: /products
          reverse_proxy: http://127.0.0.1:8090/proxy
          headers:
            - - +
              - Access-Control-Allow-Credentials
              - "true"
            - - +
              - Access-Control-Allow-Origin
              - "*"
        - rule: /
          file_server:
            root: wmproxy
            browse: true
            index:
              - index.html
              - index.htm

而json的格式結構如下:

{
  "http": {
    "gzip": "on",
    "server": [
      {
        "bind_addr": "127.0.0.1:80",
        "server_name": "wm-proxy.com",
        "location": [
          {
            "rule": "/products",
            "reverse_proxy": "http://127.0.0.1:8090/proxy",
            "headers": [
              [
                "+",
                "Access-Control-Allow-Credentials",
                "true"
              ],
              [
                "+",
                "Access-Control-Allow-Origin",
                "*"
              ]
            ]
          },
          {
            "rule": "/",
            "file_server": {
              "root": "wmproxy",
              "browse": true,
              "index": [
                "index.html",
                "index.htm"
              ]
            }
          }
        ]
      }
    ]
  }
}
  • 自建的好處是比較清晰,可以自定義自己合適的結構,但是編寫者需要重新開始學習,而用能用的組態檔需要遵循它的格式定義
  • 像toml檔案,如果層級很深,他的key值設定會很長,因為他一旦定義一個table,就是從最頂級來解析,但是編寫者只要熟悉過這組態檔很快就能寫出滿意的組態檔
  • 而yaml的層級結構相對會需要去看對齊與否,編寫的時候需要額外注意,因為弄錯了縮排,層級就會發生錯誤
  • 而json最後結尾的會有相當多的花括號,相對比較容易弄錯。JSON總體來說不太適合做比較複雜的組態檔

結語

在不考慮自建格式的情況下,如nginx的nginx.conf,如caddy的Caddyfile,將會同時相容tomlyaml格式的組態檔。