nodejs和php实现图片访问实时处理


Posted in NodeJs onJanuary 05, 2017

我在访问时光网、网易云音乐等网站时,发现将它们页面中的一些图片URL修改一下就可以得到不同尺寸的图片,于是思考了其实现方案,我的思路是:URL Rewrite + 实时处理 + 缓存,对用户请求的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=$t break;
  }
  proxy_pass    http://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模块:

npm install gm --save
接着便可以使用GraphicsMagick了,该模块的API可以参考GM模块API介绍。图片处理的实现如下:

app.get('/resize',function(req,res){
  var src = req.query.src,
    width = req.query.w,
    height = req.query.h,
    type = req.query.type;
  var imgFile = uploadDir+src+'.'+type;
  var notFound = '不好意思,该图片不存在或已被删除!';
  var thumb = 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);
  }
});
function imgResize(f,th,w,h,t,r){
  var imgSize = sizeOf(f);
  if(!w||!h||w>=imgSize.width||h>=imgSize.height){
    r.type(t).sendFile(__dirname+'/'+f);
  }else{
    imageMagick(f)
      .resize(w,h,'!') 
      .stream(function(err, stdout, stderr) {
        if (err) {
          console.log(err);
          res.end();
        }
        var ws = fs.createWriteStream(th);
        stdout.pipe(ws);
        r.type(t);
        stdout.pipe(r);
      });
  }
}
function isFileExists(filePath){
  var bool = !0;
  try{
    fs.accessSync(filePath,fs.constants.F_OK);
  }catch(err){
    bool = !1;
  }
  return bool;
}

如上代码所示,当用户访问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){
  var src = RegExp.$1,
    width = RegExp.$2,
    height = RegExp.$3,
    type = RegExp.$4;
  var imgFile = uploadDir+src+'.'+type;
  var notFound = '不好意思,该图片不存在或已被删除!';
  var thumb = 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,具体的搭建步骤网上一大堆,便不再累述。

开启apache rewrite功能

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

配置.htaccess文件

在DocumentRoot目录下,新建.htaccess文件,如果创建不了,可以先创建一个文本,然后另存为,在弹出的对话框文件名处填写".htaccess"即可。之后,编写URL重写规则,如下所示:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
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/upload/147332819224704_400x300.jpg地址重写为http://127.0.0.1/resize.php/src=147332819224704&w=400&h=300&type=jpg

功能实现

接下来便是功能的实现,逻辑和nodejs版逻辑一致,代码如下:

function getThumbImg($src,$w,$h,$type)
{
  global $thumbs;
  return $_SERVER['DOCUMENT_ROOT'].$thumbs.$src.'_'.$w.'_'.$h.'.'.$type;
}
function imgResize($f,$th,$w,$h,$t)
{
  $imagick = new Imagick();
  $imagick->readImage($_SERVER['DOCUMENT_ROOT'].'\\'.$f);
  $width = $imagick->getImageWidth();
  $height = $imagick->getImageHeight();
  if(!$w||!$h||$w>=$width||$h>=$height){
    header('Content-Type:image/'.$t);
    echo file_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);
if(file_exists($imgFile)){
  if(file_exists($thumb)){
    header('Content-Type:image/'.$type);
    echo file_get_contents($thumb);
  }else{
    imgResize($imgFile,$thumb,$width,$height,$type);
  }
}else{
  header("HTTP/1.0 404 Not Found");
  header("status: 404");
  echo $notFound;
}

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
NodeJS url验证(url-valid)的使用方法
Nov 18 NodeJs
NodeJs中的VM模块详解
May 06 NodeJs
Nodejs express框架一个工程中同时使用ejs模版和jade模版
Dec 28 NodeJs
使用NodeJs 开发微信公众号(三)微信事件交互实例
Mar 02 NodeJs
nodejs如何获取时间戳与时间差
Aug 03 NodeJs
nodejs个人博客开发第三步 载入页面
Apr 12 NodeJs
windows系统下更新nodejs版本的方案
Nov 24 NodeJs
NodeJs项目中关闭ESLint的方法
Aug 09 NodeJs
基于nodejs的雪碧图制作工具的示例代码
Nov 05 NodeJs
Nodejs中获取当前函数被调用的行数及文件名详解
Dec 12 NodeJs
nodejs npm错误Error:UNKNOWN:unknown error,mkdir 'D:\Develop\nodejs\node_global'at Error
Mar 02 NodeJs
NodeJS 文件夹拷贝以及删除功能
Sep 03 NodeJs
nodejs实例解析(输出hello world)
Jan 03 #NodeJs
Highcharts+NodeJS搭建数据可视化平台示例
Jan 01 #NodeJs
nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证示例
Dec 30 #NodeJs
浅谈Nodejs中的作用域问题
Dec 26 #NodeJs
nodeJS删除文件方法示例
Dec 25 #NodeJs
详解nodejs 文本操作模块-fs模块(五)
Dec 23 #NodeJs
详解Nodejs的timers模块
Dec 22 #NodeJs
You might like
PHP COOKIE及时生效的方法介绍
2014/02/14 PHP
php中替换字符串函数strtr()和str_repalce()的用法与区别
2016/11/25 PHP
老生常谈PHP中的数据结构:DS扩展
2017/07/17 PHP
javascript 写类方式之六
2009/07/05 Javascript
js 弹出菜单/窗口效果
2011/10/30 Javascript
如何使用jquery控制CSS样式,并且取消Css样式(如背景色,有实例)
2013/07/09 Javascript
一个简单的jquery的多选下拉框(自写)
2014/05/05 Javascript
jQuery前端框架easyui使用Dialog时bug处理
2014/12/05 Javascript
JavaScript中使用Callback控制流程介绍
2015/03/16 Javascript
全面解析Bootstrap布局组件应用
2016/02/22 Javascript
不定义JQuery插件 不要说会JQuery
2016/03/07 Javascript
仅9张思维导图帮你轻松学习Javascript 就这么简单
2016/06/01 Javascript
全面了解js中的script标签
2016/07/04 Javascript
js 获取本地文件及目录的方法(推荐)
2016/11/10 Javascript
jQuery插件zTree实现清空选中第一个节点所有子节点的方法
2017/03/08 Javascript
JavaScript简单计算人的年龄示例
2017/04/15 Javascript
js编写简单的计时器功能
2017/07/15 Javascript
js实现随机点名程序
2020/09/17 Javascript
js+css实现扇形导航效果
2020/08/18 Javascript
[01:00:06]加油DOTA_EP01_网络版
2014/08/09 DOTA
[41:52]2018DOTA2亚洲邀请赛3月29日小组赛B组Effect VS Secret
2018/03/30 DOTA
对python中list的拷贝与numpy的array的拷贝详解
2019/01/29 Python
使用Python调取任意数字资产钱包余额功能
2019/08/15 Python
Python生成个性签名图片获取GUI过程解析
2019/12/16 Python
Python面向对象之继承原理与用法案例分析
2019/12/31 Python
通过代码实例了解Python3编程技巧
2020/10/13 Python
详解使用HTML5 Canvas创建动态粒子网格动画
2016/12/14 HTML / CSS
zooplus意大利:在线宠物商店
2019/08/07 全球购物
EJB需直接实现它的业务接口或Home接口吗,请简述理由
2016/11/23 面试题
火锅店创业计划书范文
2014/02/02 职场文书
我的中国梦演讲稿小学篇
2014/08/19 职场文书
党员自我评议个人对照检查材料
2014/09/16 职场文书
民间个人借款协议书
2014/09/30 职场文书
2014年反腐倡廉工作总结
2014/12/05 职场文书
2015年施工员工作总结范文
2015/04/20 职场文书
Python爬虫之爬取哔哩哔哩热门视频排行榜
2021/04/28 Python