nginx平滑添加http_image_filter_module模块裁剪图片


项目中经常用到缩略图,特别是app端针对不同手机分辨率需要不同的图片尺寸,客户端可以通过传不同尺寸参数自动裁剪图片,类似原图名称为image.jpg,缩略图可以通过image_100x100.jpg获取100x100的缩略图,解决这个问题大概有以下几个方案:

  • 人工裁剪不同尺寸的图片(不可取)
  • 用程序裁剪(效率一般)
  • 用nginx自带扩展http_image_filter_module裁剪图片(方便快捷)

环境:ubuntu 14.04

1. 查看是否已安装http_image_filter_module模块

$ /usr/local/nginx/sbin/nginx -V

2. 重新编译nginx

由于是线上环境需要平滑升级

  • 下载nginx,如果已经有nginx,进入nginx安装文件目录
$ curl http://nginx.org/download/nginx-1.10.0.tar.gz |tar -xzf -
  • configure添加http_image_filter_module模块
$ ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module --with-http_image_filter_module

报错啦

./configure: error: the HTTP image filter module requires the GD library.
You can either do not enable the module or install the libraries.

这个扩展需要GD库,安装后再次configure

$ apt-get install libgd2-xpm-dev
  • make编译,不要make install,否则就是覆盖安装
$ make
  • 平滑替换nginx二进制文件,重命名nginx旧版本二进制文件,即sbin目录下的nginx(期间nginx并不会停止服务!)
$ mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
  • 拷贝一份新编译的二进制文件(新编译的文件在当前objs目录下)
$ cp ./objs/nginx /usr/local/nginx/sbin/
  • 在源码目录执行make upgrade开始升级
$ make upgrade
  • 完成后,最后确认一下 nginx -V,平滑升级完成 :
root@iZ25ocblen4Z:/# nginx -V
nginx version: nginx/1.10.0
built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.1)
built with OpenSSL 1.0.1f 6 Jan 2014
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_gzip_static_module --with-ipv6 --with-http_sub_module --with-http_image_filter_module

3. 修改nginx的配置文件

  • 匹配所有图片
  • 判断是否存在原图是否存在,不存在直接返回404
  • 跳转到https://127.0.0.1/image-resize/$filepath/$filename?width=$width&height=$height,将参数高和宽带到url中。
  • Image_filter resize指令根据h和w参数生成相应缩略图。
  • 保存处理后的图片
    #https://demo.com/android88_jiajia_80x80.jpg 匹配方式
    location ~* /(.*)\/([\w]+)_(\d+)x(\d+)\.(jpg|png|jpeg|gif)$ {
        if (-f $request_filename) {
            break;
        }

        set $filepath $1;
        set $filename "$2.$5";
        set $thumb    "$2_$3x$4.$5";
        set $width    $3;
        set $height   $4;

        if (!-f $document_root/$filepath/$filename) {
            return 404;
        }

        rewrite /(.*)\/([\w]+)\.(.*) /imgcache/$filepath/$2.$3;

        if (!-f $request_filename) {
        #我网站是https,根据实际情况修改
            proxy_pass https://127.0.0.1:$server_port/image-resize/$filepath/$filename?width=$width&height=$height;
            break;
        }
        # 若执行了 proxy_pass,则下面四句都是为了保存处理后的图片,以备日后的访问
        proxy_store          $document_root/imgcache/$filepath/$thumb;
        proxy_store_access   user:rw  group:rw  all:r;
        proxy_set_header     Host $host;
    }

    #https://demo.com/android88_jiajia.jpg!80x80 匹配方式
    location ~* /(.*)\/([\w]+)\.(jpg|png|jpeg|gif)!(\d+)x(\d+)$ {
        if (-f $request_filename) {
            break;
        }

        set $filepath $1;
        set $filename "$2.$3";
        set $thumb    "$2_$4x$5.$3";
        set $width    $4;
        set $height   $5;

        if (!-f $document_root/$filepath/$filename) {
            return 404;
        }

        rewrite /(.*)\/([\w]+)\.(.*) /imgcache/$filepath/$2.$3;

        if (!-f $request_filename) {
            proxy_pass https://127.0.0.1:$server_port/image-resize/$filepath/$filename?width=$width&height=$height;
            break;
        }

        proxy_store          $document_root/imgcache/$filepath/$thumb;
        proxy_store_access   user:rw  group:rw  all:r;
        proxy_set_header     Host $host;
    }

    # 匹配满足 /image_resize的URI,都是来自上面的location
    location /image-resize {
        rewrite /(image-resize)/(.*) /$2 break;
        # 根据参数,resize 找到的图片
        image_filter resize $arg_width $arg_height;
        image_filter_jpeg_quality 75;
        # 禁止外网的访问,只允许本地访问
        allow 127.0.0.0/8;
        deny all;
    }

如果文件不存在默认会返回415,通过proxy_pass的方式解决415的问题,文件不存在返回404,并通过proxy_store的方式将图片存到指定的目录(imgcache)。

4. nginx 配置文件重新加载

$ /usr/local/nginx/sbin/nginx -s reload

生成缩略图只是image_filter功能中的一个,它一共支持4种参数:

  • test:返回是否真的是图片
  • size:返回图片长短尺寸,返回json格式数据
  • corp:截取图片的一部分,从左上角开始截取,尺寸写小了,图片会被剪切
  • resize:缩放图片,等比例缩放

常常是最后一把钥匙打开了门