既然 WebP 有這麼好的優點, 檔案小品質佳, 對於網站經營者來說可以減少頻寬支出, 所以各家 CDN 業者像是 Cloudflare 的 Polish 功能直接幫網站轉 WebP 無需變動網站程式或傳統 GIF / JPG / PNG...等檔案, 在支援 WebP 的瀏覽器輸出轉換 WebP 圖片, 在 Safari 13 輸出 原本的圖片, 那沒有 CDN 怎麼辦? 本文將利用 WebP Server Go 版本搭配 Nginx Web Server 建立一個即時轉換的代理伺服器
WebP Server Go
WebP Server Go 是由 Nova Kwok 為主要開發者, 以 Go 語言編寫的伺服器軟體, 另外也有其他電腦語言的版本, 這個專案在: https://github.com/webp-sh/webp_server_go, 可在此下載最新已編譯好的伺服器軟體或原始碼來使用
在看過原始碼後, WebP Server Go 會將原本的 JPG 圖片另存一個 .webp 副檔名的 WebP 格式圖片, 例如:
test.jpg.1598510600.webp
是的, 還加上了 Unix Timestamp (1598510600) 標記轉換時間, 如果你只要單純利用 WebP Server Go 轉圖, 可以直接立即使用伺服器軟體執行檔, 我因為想輸出 test.webp, 那麼就需要修改原始碼
目前的 WebP Server Go 0.2.0 版使用 Go 1.14 編譯, 而我的測試環境是 Debian Linux 10, 預設的 Golang 套件為 1.11, 需要較新的 Golang 套件, 還好已經有 golang-1.14-go 套件可用
安裝 Golang 1.14
apt-get -t buster-backports install golang-1.14-go
編譯器將安裝到
/usr/lib/go-1.14/bin/
目錄下載 WebP Server Go 0.2.0
wget https://github.com/webp-sh/webp_server_go/archive/0.2.0.tar.gz
tar zxvf 0.2.0.tar.gz
cd webp_server_go-0.2.0
修改
webp-server.go
, 避免啟動 WebP Server Go 自動更新功能升級到最新版, 免得後續修改白費nano webp-server.go
尋找
go autoUpdate()
, 改成 // go autoUpdate()
讓自動更新無效接著修改儲存 WebP 圖片的檔案名稱規則, 打開
helper.go
程式nano helper.go
先在
import
模組下加上新的函數, 用於取得檔案名稱, 去掉副檔名func fileNameWithoutExtension(fileName string) string {
return strings.TrimSuffix(fileName, filepath.Ext(fileName))
}
此段程式來自於 https://gist.github.com/ivanzoid/129460aa08aff72862a534ebe0a9ae30
尋找
func GenWebpAbs
函數, 以下是我修改過的函數func GenWebpAbs(RawImagePath string, ExhaustPath string, ImgFilename string, reqURI string) (string, string) {
_, err := os.Stat(RawImagePath)
if err != nil {
log.Error(err.Error())
}
WebpFilename := fmt.Sprintf("%s.webp", fileNameWithoutExtension(ImgFilename))
cwd, _ := os.Getwd()
WebpAbsolutePath := path.Clean(path.Join(ExhaustPath, path.Dir(reqURI), WebpFilename))
return cwd, WebpAbsolutePath
}
修改完成後, 就可以編譯了
/usr/lib/go-1.14/bin/go build
完成編譯會有一個執行檔, 名為
webp_server_go
Nginx + WebP Server Go 服務設定
複製執行檔到系統目錄
cp webp_server_go /usr/local/bin/webp-server
輸出預設組態檔
mkdir /etc/webps
webp-server -dump-config > /etc/webps/config.json
修改設定檔
nano /etc/webps/config.json
以下是我的範例設定
{
"HOST": "127.0.0.1",
"PORT": "8080",
"QUALITY": "85",
"IMG_PATH": "/var/www/html",
"EXHAUST_PATH": "/var/www/html",
"ALLOWED_TYPES": ["jpg","png","jpeg"]
}
這個 JSON 檔案,
HOST
為監聽位址, 例如 127.0.0.1 (localhost), 或是你內網IP位址PORT
則是監聽埠號, 預設是 3333, 我用 Port 8080QUALITY
是預設 WebP 品質, 參考 Cloudflare 使用 85, 最高 100 代表最好品質IMG_PATH
圖片目錄, 通常設定跟 Web Server 的 Document Root 同個目錄EXHAUST_PATH
為轉換好的 WebP 圖片儲存目錄ALLOWED_TYPES
只允許轉換 JPEG, PNG...等MIME Type, 由於 WebP Server Go 尚未實作 GIF 動畫檔轉換, 故不使用 GIF舉例網站圖片
https://example.com/image/test.jpg
, Document Root 若是 /var/www/html
, 那麼 test.jpg 會是在 /var/www/html/image/test.jpg
, 當然也能依照你的使用情境來設定 EXHAUST_PATH
, 這個設定值可以理解為 WebP Server Go 的快取目錄輸出 systemd service 檔案
webp-server -dump-systemd > /lib/systemd/system/webp-server.service
以下是我的修改範例
[Unit]
Description=WebP Server Go
Documentation=https://github.com/webp-sh/webp_server_go
After=nginx.target
[Service]
Type=simple
StandardError=journal
WorkingDirectory=/var/www/html
ExecStart=/usr/local/bin/webp-server --config /etc/webps/config.json
Restart=always
RestartSec=3s
[Install]
WantedBy=multi-user.target
啟用 WebP Server Go 服務
systemctl enable webp-server
WebP Server Go 要在 Nginx Web Server 之後啟動, 暫且關掉 Nginx, 修改 nginx.conf 來讓 WebP Server Go 對圖片做轉換
service nginx stop
編輯 Nginx 設定檔
nano /etc/nginx/nginx.conf
以下是我的範例
upstream webps {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name _;
location ~ \.(jpg|jpeg|png)$ {
proxy_pass http://webps;
add_header Vary "Accept";
}
location / {
root /var/www/html;
index index.html index.htm;
}
}
儲存後, 啟動 Nginx
service nginx start
接著啟動 WebP Server Go
service webp-server start
實際測試
這是我的測試照片 test.jpg, 檔案大小 1,576,997 Bytes, 寬高為 1200x1920px

利用 Chrome 瀏覽器檢視圖片

用開發人員工具檢視 HTTP Response,
Content-Type
傳回 image/webp
, 你可以注意到我 Request 的是 test.jpg 而且 Header Content-Length: 270296
, 這個 WebP 圖片只有 270,296 Bytes! 與原檔 1,576,997 Bytes 差異頗大! 當然, 依照上述設定, WebP Server Go 會在 Document Root 目錄 /var/www/html
下建立 WebP 圖檔快取, 下次讀取就不用花到 700ms 了