前言

为了博客的美观采用了大量的图片,其中不乏高质量高分辨率同时导致大体积的图片,所以我就在寻找能否有一种方式可以把图片压缩并把请求重定向到压缩后的图片,以同时达到提升加载速度和减少流量消耗的目的。

于是我找到了webp-server-go这个项目。

因为提供了docker镜像所以我本来以为部署会非常简单,但是没想到出了各种各样的问题以至于在花了不少精力和时间终于解决之后我决定写一篇文章记录一下

本文并不是教程性质的文章,所以不会写的非常详细,会有比其他文章更多的吐槽和抱怨。当然如果本文中的内容能帮助到正在读文章的人我也会非常高兴。


项目简介

Webp Server Go是一个开源项目,可以自动将图片压缩成webp格式,同时配合一些反代服务可以实现将所有的图片请求自动重定向到压缩后的webp图片。

"This is a Server based on Golang, which allows you to serve WebP images on the fly."

——官方文档

如果不想大费周章的去将Webp-server-go部署到本地服务器,或者你的网站是部署在github page之类托管服务上的静态页面根本没有服务器,也可以使用这个项目的非开源服务器版本Webp Cloud。不过正如前言所述我不会介绍如何使用,这里贴个使用文档


服务本体的安装与配置

安装

使用docker-compose进行安装

首先创建项目文件夹

mkdir -p webp-server-go/{exhaust,metadata}
cd webp-server-go

接下来创建并编写docker-compose.yml ,先贴一下使用文档中给出的示例

version: '3'

services:
  webp:
    image: webpsh/webp-server-go
    restart: always
    volumes:
      - ./path/to/pics:/opt/pics
      - ./exhaust:/opt/exhaust
      - ./metadata:/opt/metadata
    ports:
      -  127.0.0.1:3333:3333

要修改的内容只有挂载文件夹的路径,其中

/opt/pics 是图片路径,事实上路径不一定要是这个,之后可以在配置文件中修改

/opt/exaust 是图片缓存路径,即生成的webp图片的暂存路径

/opt/metdata是图片元数据路径

首先为了能够更方便的修改配置,要将配置文件挂载出来

volumes:
  - ./config.json:/etc/config.json

之后就来到了第一个令我头疼的事情:原图片路径的挂载

由于我想实现无感的图片替换,所以我尝试直接将halo的附件文件夹挂载到容器内。但是并没有成功。会返回404:image not found ,同时halo所使用的其他图片资源也会被重定向从而寻找不到。经过各种尝试之后我选择在配置文件中配置IMAGE_MAP

这个IMAGE_MAP 简单来说就是webp-server-go支持将不同的请求请求定位到不同的地方,所以我干脆把所需要的请求都定位到自己创建的新文件夹,原有的/opt/pics直接不用了。具体的配置后面跟配置文件一起说

volumes:
  - path-to-halo/attachments/upload:/upload

这里又出现了一个问题。halo在2.19版本加入了缩略图和响应式图片的功能,在上传附件时会生成图片的不同尺寸的缩略图并保存在/attachments/thumbnails 中,文件结构如下

attachments/
├── thumbnails
│   └── 2024
│       ├── w1600
│       │   └── xx.jpg
│       ├── w1200
│       │   └── xx.jpg
│       └── w800
│       │   └── xx.jpg
│       └── w400
│           └──xx.jpg
└── upload
    └── xx.jpg

可以看出thumbnailsupload是在同一级文件夹下的,然而当halo访问缩略图时,请求的url却是/upload/thunbnails/xxxx/wxxx/xx.jpg ,这就导致了如果直接把thumbnails挂载到容器内的thumbnails文件夹的话请求缩略图的url并不能用来定位到该图片。刚开始我尝试了在upload文件夹内建立软链接然而并没有用

最后我尝试了简单粗暴的把thumbnails文件夹挂载到容器内的/upload/thumbnails ,像下面这样,居然成功了……

volumes:
  - /path-to-halo/attachments/upload:/upload 
  - /path-to-halo/attachments/thumbnails:/upload/thumbnails

最终的完整docker-compose.yml文件内容如下

version: "3.9"
services:

  webpgo:
    image: webpsh/webp-server-go

    volumes:
      - ./config.json:/etc/config.json 
      - /path-to-halo/attachments/upload:/upload 
      - /path-to-halo/attachments/thumbnails:/upload/thumbnails
      - ./exhaust:/opt/exhaust
      - ./metadata:/opt/metadata
    ports:
      - 3333:3333
    restart: unless-stopped
    container_name: webp-go

运行如下命令以启动镜像

docker-compose up -d

查看日志以确定容器正常启动

docker logs webp-go

配置

以下是config.json配置文件的默认内容

{
  "HOST": "0.0.0.0",
  "PORT": "3333",
  "QUALITY": "80",
  "IMG_PATH": "./pics",
  "EXHAUST_PATH": "./exhaust",
  "IMG_MAP": {},
  "ALLOWED_TYPES": ["jpg", "png", "jpeg", "bmp", "gif", "svg", "heic", "nef", "webp"],
  "CONVERT_TYPES": ["webp"],
  "STRIP_METADATA": true,
  "ENABLE_EXTRA_PARAMS": false,
  "EXTRA_PARAMS_CROP_INTERESTING": "InterestingAttention",
  "READ_BUFFER_SIZE": 4096,
  "CONCURRENCY": 262144,
  "DISABLE_KEEPALIVE": false,
  "CACHE_TTL": 259200,
  "MAX_CACHE_SIZE": 0
}

因为要处理的文件里有avif格式,所以在ALLOW_TYPES 里加入“avif”,如果不加的话服务会返回不支持的图片格式

官方文档里给的IMAGE_MAP 格式如下

"IMG_MAP": {
  "/2": "./pics2",
  "/3": "./pics3",
  "http://www.example.com": "https://docs.webp.sh"
},

冒号前为请求的URL,冒号后为重定向之后的URL,由于我只需要重定向附件图片的/upload请求,于是

"IMG_MAP": {
  	"/upload":"/upload"
  },

反代理的配置

为了能够无感替换图片,还需要配置反代理以实现将图片请求自动重定向到webp-server-go服务里

我使用的是nginx,配置如下

location /upload {
    proxy_pass http://172.17.0.1:3333;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_hide_header X-Powered-By;
    proxy_set_header HOST $http_host;
    add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
}

这里的172.17.0.1是容器访问宿主机的ip,3333是webp-server-go的端口

实现的功能就是把位置为/upload的请求都发送到webp-server-go服务

按理来说到这里就完成大功告成了。然而还是出了问题。

问题还是在于缩略图和响应式图片的功能。

halo的缩略图生成策略是如果图片的原本的大小就和缩略图的目标大小差不多就不会生成。这就导致不是所有的图片都在/thumbnails里有对应的缩略图,当halo发现请求的图片不存在时,会返回307临时重定向到原图。然而webp-server-go会直接返回404……

所以重定向的任务就交给nginx了,让nginx拦截错误信息并将请求重定向到原图。修改之后的配置如下

location /upload {

    proxy_pass http://172.10.0.1:3333;
    proxy_intercept_errors on;                  
    proxy_set_header X-Real-IP $remote_addr;
    proxy_hide_header X-Powered-By;
    proxy_set_header HOST $http_host;
    add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
    error_page 404 = @redirect_to_upload;     
}
location @redirect_to_upload {
          rewrite ^/upload/thumbnails/.*?/.*?/(.*)$ /upload/$1 permanent; 
    }

其中,

proxy_intercept_errors on; 是开启错误拦截

error_page 404 = @redirect_to_upload; 是拦截404错误并进入@redirect_to_upload进行处理

rewrite ^/upload/thumbnails/.*?/.*?/(.*)$ /upload/$1 permanent; 是通过正则表达式对请求内容进行重写,permanent是永久重定向

以上,就是我部署webp-server-go的过程以及遇到的问题和解决方案,配置完成之后可以浏览器开F12控制台看图片类型是否已经变成webp


mad怎么花了不少精力研究的东西这几句话就写完了。

喜欢折腾,但是小白