我在访问时光网、网易云音乐等网站时,发现在他们的页面中修改一些图片url可以得到不同大小的图片,于是想到了实施计划。我的思路是:URLRewrite+实时处理+缓存,将用户请求的URL重写,然后使用图片处理库对图片进行处理,然后缓存这个尺寸的图片输出给浏览器。我又用PHP和Node.js实现了一遍,基本达到了预期的效果。1、Nginx+Node.js(express)实现URL重写这里Nginx主要完成URL重写和反向代理功能。配置如下:location~/upload/{if($request_uri~*^/upload/(.+)_(\d+)x(\d+)\.(jpg|png|gif)$){set$src$1;set$w$2;set$h$3;set$t$4;rewrite./resize?src=$src&w=$w&h=$h&type=$tbreak;}proxy_passhttp://127.0.0.1:3000;}这里是一个解释:Nginx监听本地80端口,Node.js监听3000端口,当用户访问http://127.0.0.1/upload/147332819224704_400x300.jpg这样的地址时,会被代理到http://127.0.0.1:3000/resize?src=147332819224704&w=400&h=300&type=jpg去访问,看听上去是访问图片,其实不是。实时图像处理我们在Node.js中实时处理图像,进行缩放、模糊、水印等操作,然后缓存并输出到浏览器。Node.js自带的API不擅长图像处理。我们可以使用第三方库来实现。这里推荐GraphicsMagick或者ImageMagick。在使用它们之前,安装gm模块:npminstallgm--save然后你就可以使用GraphicsMagick了。模块API请参考GM模块API介绍。图片处理的实现如下:app.get('/resize',function(req,res){varsrc=req.query.src,width=req.query.w,height=req.query.h,type=req.query.type;varimgFile=uploadDir+src+'.'+type;varnotFound='抱歉,图片不存在或已被删除!';varthumb=getThumbImg(src,width,height,type);if(isFileExists(imgFile)){if(isFileExists(thumb)){res.type(type).sendFile(__dirname+'/'+thumb);}else{imgResize(imgFile,thumb,width,height,type,res);}}else{res.status(404).send(notFound);}});functionimgResize(f,th,w,h,t,r){varimgSize=sizeOf(f);if(!w||!h||w>=imgSize.width||h>=imgSize.height){r.type(t).sendFile(__dirname+'/'+f);}else{imageMagick(f).resize(w,h,'!').流(函数(错误,标准输出,标准错误){if(错误){console.log(错误);res.end();}varws=fs.createWriteStream(th);stdout.pipe(ws);r.type(t);stdout.pipe(r);});}}functionisFileExists(filePath){varbool=!0;try{fs.accessSync(filePath,fs.constants.F_OK);}catch(err){bool=!1;}returnbool;}如上代码所示,当用户访问http://127.0.0.1/upload/147332819224704_400x300.jpg时,如果保存图片147332819224704有,而且400x300的尺寸也存在,那么直接输出这张图片,如果没有,生成一张这个尺寸的图片保存后输出到浏览器如果提供的尺寸超过图片原尺寸,直接输出原图图片。我们不仅可以修改尺寸,还可以进行模糊、加水印等操作,这里不再介绍。如果不使用Nginx反向代理,也可以使用express的常规路由实现,如下图:app.get(/^\/upload\/(.+)_(\d+)x(\d+)\.(jpg|png|gif)$/,function(req,res){varsrc=RegExp.$1,width=RegExp.$2,height=RegExp.$3,type=RegExp.$4;varimgFile=uploadDir+src+'.'+type;varnotFound='抱歉,图片不存在或已被删除!';varthumb=getThumbImg(src,width,height,type);if(isFileExists(imgFile)){if(isFileExists(thumb)){res.type(type).sendFile(__dirname+'/'+thumb);}else{imgResize(imgFile,thumb,width,height,type,res);}}else{res.status(404).send(notFound);}});2。要实现Apache+PHP,首先需要搭建windows下的php开发环境。我用的是apache2+php5.6。开启apacherewrite功能首先我们要开启apacherewritemodule功能,去掉配置文件http.conf中LoadModulerewritemodulemodules/modrewrite.so前面的注释,然后在Directory块下设置AllowOverrideAll,有可能多处,然后重启Apache服务。配置.htaccess文件在DocumentRoot目录中,创建一个新的.htaccess文件。如果无法创建,可以先创建一个文本,然后另存为,在弹出的对话框的文件名中填入“.htaccess”。之后写入URL重写规则如下:RewriteEngineonRewriteCond%{REQUEST_FILENAME}!-fRewriteRule^upload/(.+)_([0-9]+)x([0-9]+)\.(jpg|png|gif)$resize.php?src=$1&w=$2&h=$3&type=$4[L]将类似http://127.0.0.1/upload/147332819224704_400x300.jpg的地址重写为http://127.0.0.1/resize.php/src=147332819224704&w=400&h=300&type=jpg。功能实现接下来是功能实现,逻辑和nodejs版本的逻辑一致,代码如下:functiongetThumbImg($src,$w,$h,$type){global$thumbs;return$_SERVER['DOCUMENT_ROOT'].$thumbs.$src.'_'.$w.'_'.$h.'.'.$type;}functionimgResize($f,$th,$w,$h,$t){$imagick=newImagick();$imagick->readImage($_SERVER['DOCUMENT_ROOT'].'\\'.$f);$width=$imagick->getImageWidth();$height=$imagick->getImageHeight();if(!$w||!$h||$w>=$width||$h>=$height){header('Content-Type:image/'.$t);echofile_get_contents($_SERVER['DOCUMENT_ROOT'].'\\'.$f);}else{$imagick->stripImage();$imagick->cropThumbnailImage($w,$h);$imagick->writeImage($th);header('Content-Type:image/'.$t);echo$imagick->getImageBlob();$imagick->clear();$imagick->destroy();}}$uploadDir="uploads/images/";$thumbs="uploads/thumbs/";$src=$_GET['src'];$width=$_GET['w'];$height=$_GET['h'];$type=$_GET['type'];$imgFile=$uploadDir.$src.'.'.$type;$notFound='对不起,图片不存在或已被删除!';$thumb=getThumbImg($src,$width,$height,$type);如果(菲尔e_exists($imgFile)){if(file_exists($thumb)){header('Content-Type:image/'.$type);echofile_get_contents($thumb);}else{imgResize($imgFile,$thumb,$width,$height,$type);}}else{header("HTTP/1.0404NotFound");header("status:404");echo$notFound;}至此图片访问的实时处理完成.其实大部分的图片服务器都需要这样的功能,而不是预先生成几套尺寸的图片。
