如何创建并提供WebP图片以加速您的网站

作者选择Apache Software Foundation作为Write for DOnations计划的一部分,获得200美元的捐赠。

介绍

WebP是由Google在2010年基于VP8视频格式开发的一种开放图像格式。 从那时起,使用WebP格式的网站和移动应用程序的数量快速增长。 Google Chrome和Opera本身都支持WebP格式,并且由于这些浏览器约占网络流量的74%,所以如果这些网站使用WebP图像,用户可以更快地访问网站。 还有计划在Firefox中实施WebP

WebP格式支持有损和无损图像压缩,包括动画。 它比Web上使用的其他图像格式的主要优势是其文件大小更小,这使得网页加载速度更快,并减少了带宽使用量。 使用WebP图像可能导致页面速度大幅增加 如果您的应用程序或网站遇到性能问题或流量增加,转换图像可能有助于优化网页性能。

在本教程中,您将使用命令行工具cwebp将图像转换为WebP格式,从而创建将在特定目录中观看和转换图像的脚本。 最后,您将探索两种将WebP图像提供给访问者的方式。

先决条件

使用WebP图像不需要特定的分发,但我们将演示如何在Ubuntu 16.04和CentOS 7上使用相关软件。要学习本教程,您需要:

第1步 - 安装cwebp和准备图像目录

在本节中,我们将安装软件来转换图像并创建一个包含图像的目录作为测试措施。

在Ubuntu 16.04上,您可以安装cwebp ,这是一种将图像压缩为.webp格式的实用程序,方法是键入以下内容:

sudo apt-get update
sudo apt-get install webp 

在CentOS 7上,键入:

sudo yum install libwebp-tools

要在Apache Web根目录(默认位于/var/www/html )中创建一个名为webp的新映像目录,请键入:

sudo mkdir /var/www/html/webp

将此目录的所有权更改为您的非root用户sammy

sudo chown sammy: /var/www/html/webp

要测试命令,您可以使用wget下载免费的JPEG和PNG图像。 该工具默认安装在Ubuntu 16.04上; 如果您使用的是CentOS 7,则可以通过键入以下命令来安装它:

sudo yum install wget

接下来,使用以下命令下载测试图像:

wget -c "https://www.youcl.com/uploads/wikipedia/commons/2/24/Junonia_orithya-Thekkady-2016-12-03-001.jpg?download" -O /var/www/html/webp/image1.jpg
wget -c "https://www.youcl.com/uploads/wikipedia/commons/5/54/Mycalesis_junonia-Thekkady.jpg" -O /var/www/html/webp/image2.jpg
wget -c "https://www.youcl.com/uploads/photo/2017/07/18/15/39/dental-care-2516133_640.png" -O /var/www/html/webp/logo.png

注意 :这些图像可在Creative Commons Attribution-ShareAlike许可Public Domain Dedication下使用和重新分配。

下一步中的大部分工作将位于/var/www/html/webp目录中,您可以通过键入以下命令来进行操作:

cd /var/www/html/webp

通过安装测试映像以及安装了Apache Web服务器, mod_rewritecwebp ,您就可以开始转换映像。

第2步 - 使用cwebp压缩图像文件

为网站访问者提供.webp图像需要.webp版本的图像文件。 在这一步中,您将使用cwebp将JPEG和PNG图像转换为.webp格式。 该命令的一般语法如下所示:

cwebp image.jpg -o image.webp

-o选项指定WebP文件的路径。

由于您仍然位于/var/www/html/webp目录中,因此可以运行以下命令将image1.jpg转换为image1.webpimage2.jpg转换为image2.webp

cwebp -q 100 image1.jpg -o image1.webp
cwebp -q 100 image2.jpg -o image2.webp

将质量因子-q设置为100将保留100%的图像质量; 如果未指定,则默认值为75。

接下来,使用ls命令检查JPEG和WebP图像的大小。 -l选项将显示长列表格式,其中包括文件的大小, -h选项将确保ls打印出人类可读的大小:

ls -lh image1.jpg image1.webp image2.jpg image2.webp
Output-rw-r--r-- 1 sammy sammy 7.4M Oct 28 23:36 image1.jpg
-rw-r--r-- 1 sammy sammy 3.9M Feb 18 16:46 image1.webp
-rw-r--r-- 1 sammy sammy  16M Dec 18  2016 image2.jpg
-rw-r--r-- 1 sammy sammy 7.0M Feb 18 16:59 image2.webp

ls命令的输出显示image1.jpg的大小为7.4M,而image1.webp的大小为3.9M。 image2.jpg (16M)和image2.webp (7M)也是如此。 这些文件几乎是其原始大小的一半!

要在压缩过程中保存图像的完整原始数据,可以使用-lossless选项代替-q 这是保持PNG图像质量的最佳选择。 要转换第1步中下载的PNG图像,请键入:

cwebp -lossless logo.png -o logo.webp

以下命令显示无损WebP图像大小(60K)大约是原始PNG图像大小的一半(116K):

ls -lh logo.png logo.webp
Output-rw-r--r-- 1 sammy sammy 116K Jul 18  2017 logo.png
-rw-r--r-- 1 sammy sammy  60K Feb 18 16:42 logo.webp

/var/www/html/webp目录中的转换后的WebP图像比JPEG和PNG对应的图像大约小50%。 实际上,压缩率可能会因某些因素而异:原始图像的压缩率,文件格式,转换类型(有损或无损),质量百分比和操作系统。 在转换更多图像时,您可能会看到与这些因素相关的转化率的变化。

第3步 - 转换目录中的JPEG和PNG图像

编写脚本将通过消除手动转换的工作来简化转换过程。 现在我们将编写一个转换脚本来查找JPEG文件并将其转换为90%质量的WebP格式,同时还可将PNG文件转换为无损WebP图像。

使用nano或您最喜欢的编辑器,在用户的主目录中创建webp-convert.sh脚本:

nano ~/webp-convert.sh

脚本的第一行如下所示:

〜/ webp-convert.sh
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \)

该行包含以下组件:

  • :该命令将搜索指定目录内的文件。
  • $1 :这个位置参数指定了从命令行获取的images目录的路径。 最终,它使目录的位置更少地依赖于脚本的位置。
  • -type f :该选项告诉find仅查找常规文件。
  • -iname :该测试将文件名与指定模式进行匹配。 不区分大小写的-iname测试告诉find.jpg*.jpg )或.jpeg*.jpeg )结尾的任何文件名。
  • -o :这个逻辑运算符指示find命令列出匹配第一次测试( -iname "*.jpg"第二次( -iname "*.jpeg" )的文件。
  • () :围绕这些测试的括号以及-and操作符确保始终执行第一个测试(即-type f )。

脚本的第二行将使用-exec参数将图像转换为WebP。 这个参数的一般语法是-exec command {} \; 字符串{}被替换为该命令迭代的每个文件,而; 告诉find命令结束的地方:

〜/ webp-convert.sh
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c 'commands' {} \;

在这种情况下, -exec参数将需要多个命令来搜索和转换图像:

  • bash :这个命令将执行一个小脚本,如果该脚本不存在,它将创建文件的.webp版本。 由于-c选项,该脚本将作为字符串传递给bash
  • 'commands' :这个占位符是可以制作文件的.webp版本的脚本。

'commands'的脚本将执行以下操作:

  • 创建一个webp_path变量。
  • 测试文件的.webp版本是否存在。
  • 如果该文件不存在,请将其制作。

较小的脚本看起来像这样:

〜/ webp-convert.sh
...
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then 
  cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;

这个较小的脚本中的元素包括:

  • webp_path :该变量将使用sedbash命令中的匹配文件名生成,由位置参数$0 这里的字符串<<< )将把这个名字传递给sed
  • if [ ! -f "$webp_path" ] if [ ! -f "$webp_path" ] :此测试将使用逻辑not运算符( ! )确定名为"$webp_path"的文件是否已存在。
  • cwebp :如果文件不存在,该命令将使用-q选项创建该文件,以便不打印输出。

使用这个较小的脚本代替'commands'占位符,转换JPEG图像的完整脚本现在将如下所示:

〜/ webp-convert.sh
# converting JPEG images
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then 
  cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;' {} \;

要将PNG图像转换为WebP,我们将采用相同的方法,但有两点不同:首先, find命令中的-iname模式将为"*.png" 其次,转换命令将使用-lossless选项而不是质量-q选项。

完成的脚本如下所示:

〜/ webp-convert.sh
#!/bin/bash

# converting JPEG images
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then 
  cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;' {} \;

# converting PNG images
find $1 -type f -and -iname "*.png" \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then 
  cwebp -quiet -lossless "$0" -o "$webp_path";
fi;' {} \;

保存文件并退出编辑器。

接下来,让我们使用/var/www/html/webp目录中的文件来实践webp-convert.sh脚本。 通过运行以下命令确保脚本文件可执行:

chmod a+x ~/webp-convert.sh

在images目录上运行脚本:

./webp-convert.sh /var/www/html/webp

什么都没发生! 这是因为我们已经在第2步中转换了这些图像。向前移动,当我们添加新文件或删除.webp版本时, webp-convert脚本将转换图像。 要查看这是如何工作的,请删除我们在第2步中创建的.webp文件:

rm /var/www/html/webp/*.webp

删除所有.webp图像后,再次运行该脚本以确保其正常工作:

./webp-convert.sh /var/www/html/webp

ls命令将确认脚本已成功转换图像:

ls -lh /var/www/html/webp
Output-rw-r--r-- 1 sammy sammy 7.4M Oct 28 23:36 image1.jpg
-rw-r--r-- 1 sammy sammy 3.9M Feb 18 16:46 image1.webp
-rw-r--r-- 1 sammy sammy  16M Dec 18  2016 image2.jpg
-rw-r--r-- 1 sammy sammy 7.0M Feb 18 16:59 image2.webp
-rw-r--r-- 1 sammy sammy 116K Jul 18  2017 logo.png
-rw-r--r-- 1 sammy sammy  60K Feb 18 16:42 logo.webp

此步骤中的脚本是在您的站点中使用WebP图像的基础,因为您需要WebP格式的所有图像的工作版本才能为访问者提供服务。 下一步将介绍如何自动转换新图像。

第4步 - 观看目录中的图像文件

在这一步中,我们将创建一个新脚本来观看我们的图像目录中的更改并自动转换新创建的图像。

创建一个webp-convert.sh我们图像目录的脚本可以解决webp-convert.sh脚本写入时的某些问题。 例如,这个脚本不会识别我们是否重命名了一个图像。 如果我们有一个名为foo.jpg的图像,运行webp-convert.sh ,重命名该文件bar.jpg ,然后再次运行webp-convert.sh ,我们将重复使用.webp文件( foo.webpbar.webp ) 。 为了解决这个问题,并避免手动运行脚本,我们将添加监视器到另一个脚本。 观察者观察指定的文件或目录以进行更改,并运行命令以响应这些更改。

inotifywait命令将在我们的脚本中设置观察者。 该命令是inotify-tools软件包的一部分,该软件包是一组命令行工具,为inotify内核子系统提供了一个简单的接口。 要在Ubuntu 16.04上安装它,请键入:

sudo apt-get install inotify-tools

借助CentOS 7,EPOT存储库中提供了inotify-tools软件包。 使用以下命令安装EPEL存储库和inotify-tools软件包:

sudo yum install epel-release
sudo yum install inotify-tools

接下来,使用nano在用户的主目录中创建webp-watchers.sh脚本:

nano ~/webp-watchers.sh

脚本中的第一行将如下所示:

〜/ webp-watchers.sh
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1

该行包含以下内容:

  • inotifywait :该命令inotifywait对某个目录的更改。
  • -q :该选项会告诉inotifywait安静,不会产生大量输出。
  • -m :此选项将告诉inotifywait无限期运行,并且在收到单个事件后不会退出。
  • -r :该选项将递归地设置观察者,观察指定的目录及其所有子目录。
  • --format :此选项告诉inotifywait使用事件名称跟踪文件路径来监视更改。 我们要监视的事件是close_write (当文件被创建并完全写入磁盘时触发), moved_frommoved_to (当文件被移动时触发),以及delete (当文件被删除时触发)。
  • $1 :该位置参数保存更改文件的路径。

接下来,我们添加一个grep命令来确定我们的文件是JPEG还是PNG图像。 -i选项将告诉grep忽略大小写, -E将指定grep应该使用扩展正则表达式,而--line-buffered将告诉grep将匹配的行传递给while循环:

〜/ webp-watchers.sh
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 | grep -i -E '\.(jpe?g|png)$' --line-buffered

接下来,我们将使用read命令构建一个while循环。 read将处理inotifywait检测到的事件,将其分配给名为$operation的变量,并将处理后的文件路径分配给名为$path的变量:

〜/ webp-watchers.sh
...
| while read operation path; do
  # commands
done;

让我们将这个循环与脚本的其余部分结合起来:

〜/ webp-watchers.sh
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 \
| grep -i -E '\.(jpe?g|png)$' --line-buffered \
| while read operation path; do
  # commands
done;

while循环检查事件后,循环内的命令将根据结果采取以下操作:

  • 如果新图像文件已创建或移动到目标目录,请创建一个新的WebP文件。
  • 如果关联的图像文件已从目标目录中删除或移动,请删除WebP文件。

循环内有三个主要部分。 名为webp_path的变量将保存主题图像的.webp版本的路径:

〜/ webp-watchers.sh
...
webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")";

接下来,该脚本将测试发生了哪个事件:

〜/ webp-watchers.sh
...
if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then
  # commands to be executed if the file is moved or deleted
elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then
  # commands to be executed if a new file is created
fi;

如果文件已被移动或删除,脚本将检查.webp版本是否存在。 如果是这样,脚本将使用rm将其删除:

〜/ webp-watchers.sh
...
if [ -f "$webp_path" ]; then
  $(rm -f "$webp_path");
fi;

对于新创建的文件,压缩将发生如下:

  • 如果匹配的文件是PNG图像,则脚本将使用无损压缩。
  • 如果不是,脚本将使用-quality选项进行有损压缩。

让我们添加将完成这项工作的cwebp命令给脚本:

〜/ webp-watchers.sh
...
if [ $(grep -i '\.png$' <<< "$path") ]; then
  $(cwebp -quiet -lossless "$path" -o "$webp_path");
else
  $(cwebp -quiet -q 90 "$path" -o "$webp_path");
fi;

完整的webp-watchers.sh文件将如下所示:

〜/ webp-watchers.sh
#!/bin/bash
echo "Setting up watches.";

# watch for any created, moved, or deleted image files
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 \
| grep -i -E '\.(jpe?g|png)$' --line-buffered \
| while read operation path; do
  webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")";
  if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then # if the file is moved or deleted
    if [ -f "$webp_path" ]; then
      $(rm -f "$webp_path");
    fi;
  elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then  # if new file is created
     if [ $(grep -i '\.png$' <<< "$path") ]; then
       $(cwebp -quiet -lossless "$path" -o "$webp_path");
     else
       $(cwebp -quiet -q 90 "$path" -o "$webp_path");
     fi;
  fi;
done;

保存并关闭文件。 不要忘记让它可执行:

chmod a+x ~/webp-watchers.sh

我们使用&在后台的/var/www/html/webp目录中运行此脚本。 我们还将标准输出和标准错误重定向到~/output.log ,以将输出存储在一个易于使用的位置:

./webp-watchers.sh /var/www/html/webp > output.log 2>&1 &

此时,您已将/var/www/html/webp的JPEG和PNG文件转换为WebP格式,并设置观察者使用webp-watchers.sh脚本完成此项工作。 现在是时候探索将WebP图像传递给网站访问者的选项。

第5步 - 使用HTML元素将WebP图像提供给访问者

在这一步中,我们将解释如何为HTML元素提供WebP图像。 此时, /var/www/html/webp目录中应包含每个测试JPEG和PNG图像的.webp版本。 现在我们可以使用HTML5元素( <picture> )或mod_rewrite Apache模块来支持浏览器。 我们将在这一步中使用HTML元素。

<picture>元素允许您直接在网页中包含图像并定义多个图像源。 如果您的浏览器支持WebP格式,它将下载该文件的.webp版本而不是原来的版本,从而加快网页的.webp速度。 值得一提的是,在支持WebP格式的现代浏览器中, <picture>元素得到了很好的支持。

<picture>元素是一个包含指向特定文件的<source><img>元素的容器。 如果我们使用<source>指向一个.webp图片,浏览器将会看到它是否可以处理它; 否则,它将回退到<img>元素中src属性中指定的图像文件。

我们使用我们的/var/www/html/webp目录中的logo.png文件,将其转换为logo.webp ,作为<source>的示例。 我们可以使用以下HTML代码将logo.webp显示给任何支持WebP格式的浏览器,以及将logo.png给任何不支持WebP或<picture>元素的浏览器。

创建位于/var/www/html/webp/picture.html的HTML文件:

nano /var/www/html/webp/picture.html

将以下代码添加到网页以显示logo.webp以支持使用<picture>元素的浏览器:

/var/www/html/webp/picture.html
<picture>
  <source srcset="logo.webp" type="image/webp">
  <img src="logo.png" alt="Site Logo">
</picture>

保存并关闭文件。

要测试一切正常,请导航到http:// your_server_ip /webp/picture.html 你应该看到测试PNG图像。

现在您已经知道如何直接从HTML代码提供.webp图片了,让我们看看如何使用Apache的mod_rewrite模块自动执行此过程。

第6步 - 使用mod_rewrite提供WebP图像

如果我们想优化网站的速度,但是有大量的页面或者编辑HTML代码的时间太少,那么Apache的mod_rewrite模块可以帮助我们将.webp图片的服务过程自动化为支持浏览器。

首先,使用以下命令在/var/www/html/webp目录中创建一个.htaccess文件:

nano /var/www/html/webp/.htaccess

ifModule指令将测试mod_rewrite是否可用; 如果是的话,可以使用RewriteEngine On来激活它。 将这些指令添加到.htaccess

/var/www/html/webp/.htaccess
<ifModule mod_rewrite.c>
  RewriteEngine On 
  # further directives
</IfModule>

Web服务器将进行多次测试,以确定何时向用户提供.webp图像。 当浏览器发出请求时,它会包含一个标头,以向服务器指示浏览器能够处理的内容。 在WebP的情况下,浏览器将发送包含image/webpAccept头。 我们将检查浏览器是否使用RewriteCond发送了该头文件,该文件指定了为执行RewriteRule应匹配的条件:

/var/www/html/webp/.htaccess
...
RewriteCond %{HTTP_ACCEPT} image/webp

一切都应该被过滤掉,但JPEG和PNG图像。 再次使用RewriteCond ,添加一个正则表达式(类似于我们在前面的章节中使用的)以匹配请求的URI:

/var/www/html/webp/.htaccess
...
RewriteCond %{REQUEST_URI}  (?i)(.*)(\.jpe?g|\.png)$ 

(?i)修饰符将使匹配不区分大小写。

要检查文件的.webp版本是否存在,请按如下所示再次使用RewriteCond

/var/www/html/webp/.htaccess
...
RewriteCond %{DOCUMENT_ROOT}%1.webp -f

最后,如果所有先前的条件都满足, RewriteRule会将请求的JPEG或PNG文件重定向到其关联的WebP文件。 请注意,这将使用-R标志进行重定向 ,而不是重写 URI。 重写和重定向的区别在于服务器将在不告知浏览器的情况下提供重写的URI。 例如,URI将显示文件扩展名为.png ,但它实际上是一个.webp文件。 RewriteRule添加到文件中:

/var/www/html/webp/.htaccess
...
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R] 

此时, .htaccess文件中的mod_rewrite部分已完成。 但是,如果服务器和客户端之间存在中间缓存服务器,会发生什么情况? 它可能会向最终用户提供错误的版本。 这就是为什么值得检查mod_headers是否被启用,以便发送Vary: Accept头的原因。 Vary头部指示缓存服务器(如代理服务器)根据请求文档的浏览器的功能,文档的内容类型会有所不同。 而且,响应将根据请求中的Accept标头生成。 具有不同Accept头的请求可能会得到不同的响应。 此标头非常重要,因为它可防止将缓存的WebP图像提供给非支持的浏览器:

/var/www/html/webp/.htaccess
...
<IfModule mod_headers.c>
  Header append Vary Accept env=REDIRECT_accept
</IfModule>

最后,在.htaccess文件的末尾,使用AddType指令将.webp图像的MIME类型设置为image/webp 这将使用正确的MIME类型提供图像:

/var/www/html/webp/.htaccess
...
AddType image/webp .webp

这是我们的.htaccess文件的最终版本:

/var/www/html/webp/.htaccess
<ifModule mod_rewrite.c>
  RewriteEngine On 
  RewriteCond %{HTTP_ACCEPT} image/webp
  RewriteCond %{REQUEST_URI}  (?i)(.*)(\.jpe?g|\.png)$ 
  RewriteCond %{DOCUMENT_ROOT}%1.webp -f
  RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R] 
</IfModule>

<IfModule mod_headers.c>
  Header append Vary Accept env=REDIRECT_accept
</IfModule>

AddType image/webp .webp

注意 :您可以将此.htaccess与其他.htaccess文件(如果存在)合并。 例如,如果您使用的是WordPress,您应该复制此.htaccess文件并将其粘贴到现有文件的顶部

让我们把这一步所做的一切付诸实践。 如果您按照前面的步骤进行操作,则应该在/var/www/html/webp logo.webp logo.pnglogo.webp图像。 让我们使用一个简单的<img>标签在我们的网页中加入logo.png 创建一个新的HTML文件来测试设置:

nano /var/www/html/webp/img.html

在文件中输入以下HTML代码:

/var/www/html/webp/img.html
<img src="logo.png" alt="Site Logo">

保存并关闭文件。

当您通过访问http:// your_server_ip /webp/img.html使用Chrome访问http:// your_server_ip /webp/img.html ,您会注意到提供的图像是.webp版本(尝试在新标签中打开图像)。 如果您使用Firefox,您将自动获得.png图像。

结论

在本教程中,我们介绍了使用WebP图像的基本技巧。 我们已经解释了如何使用cwebp转换文件,以及向用户提供这些图像的两个选项:HTML5的<picture>元素和Apache的mod_rewrite

为了从本教程中定制脚本,您可以查看以下某些资源:

  • 要详细了解WebP格式的功能以及如何使用转换工具,请参阅WebP文档
  • 要查看有关<picture>元素使用情况的更多详细信息,请参阅其关于MDN的文档
  • 要充分了解如何使用mod_rewrite ,请参阅其文档

使用WebP格式为您的图像将减少相当数量的文件大小。 这可以降低带宽使用量并加快页面加载速度,尤其是在您的网站使用大量图像的情况下。

赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏