UDN-企业互联网技术人气社区

板块导航

浏览  : 761
回复  : 2

[Nodejs] 图片访问实时处理的实现(nodejs和php)

[复制链接]
葡萄柚的头像 楼主
发表于 2017-2-5 10:24:33 | 显示全部楼层 |阅读模式
  我在访问时光网、网易云音乐等网站时,发现将它们页面中的一些图片URL修改一下就可以得到不同尺寸的图片,于是思考了其实现方案,我的思路是: URL Rewrite + 实时处理 + 缓存 ,对用户请求的URL进行重写,然后利用图片处理类库对图片进行处理,接着缓存该尺寸图片并输出到浏览器。使用PHP和Node.js实现了一遍,基本达到了需要的效果。

  1、Nginx+Node.js(express)实现

  URL重写

  这里Nginx主要是做一个URL重写和反向代理的功能,配置如下所示:
  1. location ~ /upload/{
  2.     if ($request_uri ~* ^/upload/(.+)_(\d+)x(\d+)\.(jpg|png|gif)$) {
  3.         set $src $1;
  4.         set $w $2;
  5.         set $h $3;
  6.         set $t $4;
  7.         rewrite . /resize?src=$src&w=$w&h=$h&type=$t break;
  8.     }
  9.     proxy_pass        http://127.0.0.1:3000;
  10. }
复制代码

  这里说明一下:Nginx监听本地的80端口,Node.js监听的是3000端口。当用户访问类似 的地址时,便会被代理到 http://127.0.0.1:3000/resize?src=147332819224704&w=400&h=300&type=jpg 访问,看起来像是访问一张图片,其实不然。

  图片实时处理

  我们在Node.js中实时处理图片,进行缩放、模糊、水印等操作,之后将其缓存起来并输出到浏览器。Node.js自身API并不擅长图片的处理,我们可以借助第三方类库来实现,这里推荐GraphicsMagick或ImageMagick,使用它们之前先安装 gm 模块:
  1. npm install gm --save
复制代码

  接着便可以使用GraphicsMagick了,该模块的API可以参考 GM模块API介绍 。图片处理的实现如下:
  1. app.get('/resize',function(req,res){
  2.     var src = req.query.src,
  3.         width = req.query.w,
  4.         height = req.query.h,
  5.         type = req.query.type;
  6.     var imgFile = uploadDir+src+'.'+type;
  7.     var notFound = '不好意思,该图片不存在或已被删除!';
  8.     var thumb = getThumbImg(src,width,height,type);
  9.     if(isFileExists(imgFile)){
  10.         if(isFileExists(thumb)){
  11.             res.type(type).sendFile(__dirname+'/'+thumb);
  12.         }else{
  13.             imgResize(imgFile,thumb,width,height,type,res);
  14.         }
  15.     }else{
  16.         res.status(404).send(notFound);
  17.     }
  18. });
  19. function imgResize(f,th,w,h,t,r){
  20.     var imgSize = sizeOf(f);
  21.     if(!w||!h||w>=imgSize.width||h>=imgSize.height){
  22.         r.type(t).sendFile(__dirname+'/'+f);
  23.     }else{
  24.         imageMagick(f)
  25.             .resize(w,h,'!')
  26.             .stream(function(err, stdout, stderr) {
  27.                 if (err) {
  28.                     console.log(err);
  29.                     res.end();
  30.                 }
  31.                 var ws = fs.createWriteStream(th);
  32.                 stdout.pipe(ws);
  33.                 r.type(t);
  34.                 stdout.pipe(r);
  35.             });
  36.     }
  37. }
  38. function isFileExists(filePath){
  39.     var bool = !0;
  40.     try{
  41.         fs.accessSync(filePath,fs.constants.F_OK);
  42.     }catch(err){
  43.         bool = !1;
  44.     }
  45.     return bool;
  46. }
复制代码

  如上代码所示,当用户访问 时,如果147332819224704这张图片存在,且400x300这个尺寸也存在,则直接输出这张图片,如不存在,则生成一张该尺寸的图片保存并输出到浏览器。如果提供的尺寸超出了图片的原始尺寸,则直接输出原图。我们不仅可以修改尺寸,也可以进行模糊、打水印等操作,这里就不多介绍了。

  如果不用Nginx反向代理也是可以的,使用express的正则路由实现,如下所示:
  1. app.get(/^\/upload\/(.+)_(\d+)x(\d+)\.(jpg|png|gif)$/,function(req,res){
  2.     var src = RegExp.$1,
  3.         width = RegExp.$2,
  4.         height = RegExp.$3,
  5.         type = RegExp.$4;
  6.     var imgFile = uploadDir+src+'.'+type;
  7.     var notFound = '不好意思,该图片不存在或已被删除!';
  8.     var thumb = getThumbImg(src,width,height,type);
  9.     if(isFileExists(imgFile)){
  10.         if(isFileExists(thumb)){
  11.             res.type(type).sendFile(__dirname+'/'+thumb);
  12.         }else{
  13.             imgResize(imgFile,thumb,width,height,type,res);
  14.         }
  15.     }else{
  16.         res.status(404).send(notFound);
  17.     }
  18. });
复制代码

  2、Apache+PHP实现

  首先得搭建windows下php开发环境,我本人用的是apache2+php5.6,具体的搭建步骤网上一大堆,便不再累述。

  开启apache rewrite功能

  首先我们得开启Apache rewrite模块功能,去掉配置文件http.conf中LoadModule rewrite_module modules/mod_rewrite.so前面的注释,然后设置Directory块下AllowOverride All,可能有多处,接着重启Apache服务。

  配置.htaccess文件

  在DocumentRoot目录下,新建 .htaccess 文件,如果创建不了,可以先创建一个文本,然后另存为,在弹出的对话框文件名处填写".htaccess"即可。之后,编写URL重写规则,如下所示:
  1. RewriteEngine on
  2. RewriteCond %{REQUEST_FILENAME} !-f
  3. RewriteRule ^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/resize.php/src=147332819224704&w=400&h=300&type=jpg
  功能实现

  接下来便是功能的实现,逻辑和nodejs版逻辑一致,代码如下:
  1. function getThumbImg($src,$w,$h,$type)
  2. {
  3.     global $thumbs;
  4.     return $_SERVER['DOCUMENT_ROOT'].$thumbs.$src.'_'.$w.'_'.$h.'.'.$type;
  5. }
  6. function imgResize($f,$th,$w,$h,$t)
  7. {
  8.     $imagick = new Imagick();
  9.     $imagick->readImage($_SERVER['DOCUMENT_ROOT'].'\\'.$f);
  10.     $width = $imagick->getImageWidth();
  11.     $height = $imagick->getImageHeight();
  12.     if(!$w||!$h||$w>=$width||$h>=$height){
  13.         header('Content-Type:image/'.$t);
  14.         echo file_get_contents($_SERVER['DOCUMENT_ROOT'].'\\'.$f);
  15.     }else{
  16.         $imagick->stripImage();
  17.         $imagick->cropThumbnailImage($w, $h);
  18.         $imagick->writeImage($th);
  19.         header('Content-Type:image/'.$t);
  20.         echo $imagick->getImageBlob();
  21.         $imagick->clear();
  22.         $imagick->destroy();
  23.     }
  24. }

  25. $uploadDir = "uploads/images/";
  26. $thumbs = "uploads/thumbs/";
  27. $src = $_GET['src'];
  28. $width = $_GET['w'];
  29. $height = $_GET['h'];
  30. $type = $_GET['type'];
  31. $imgFile = $uploadDir.$src.'.'.$type;
  32. $notFound = '不好意思,该图片不存在或已被删除!';
  33. $thumb = getThumbImg($src,$width,$height,$type);
  34. if(file_exists($imgFile)){
  35.     if(file_exists($thumb)){
  36.         header('Content-Type:image/'.$type);
  37.         echo file_get_contents($thumb);
  38.     }else{
  39.         imgResize($imgFile,$thumb,$width,$height,$type);
  40.     }
  41. }else{
  42.     header("HTTP/1.0 404 Not Found");
  43.     header("status: 404");
  44.     echo $notFound;
  45. }
复制代码

  至此,图片访问实时处理也就完成了。其实大部分图片服务器都需要这样的功能,而不是事先生成好几套尺寸的图片。

相关帖子

发表于 2017-2-5 10:25:13 | 显示全部楼层
回帖支持下楼主,请眼熟我,我叫“━殺神絶孌—“
使用道具 举报

回复

发表于 2017-2-5 10:25:13 | 显示全部楼层
OMG!介是啥东东
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部