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调用cmd命令实现复制目录
May 04 NodeJs
快速掌握Node.js之Window下配置NodeJs环境
Mar 21 NodeJs
NodeJS创建基础应用并应用模板引擎
Apr 12 NodeJs
Express与NodeJs创建服务器的两种方法
Feb 06 NodeJs
nodejs搭建本地http服务器教程
Mar 13 NodeJs
Nodejs+express+ejs简单使用实例代码
Sep 18 NodeJs
nodejs实现范围请求的实现代码
Oct 12 NodeJs
nodejs基础之多进程实例详解
Dec 27 NodeJs
Nodejs中怎么实现函数的串行执行
Mar 02 NodeJs
详解NodeJS Https HSM双向认证实现
Mar 12 NodeJs
nodejs nedb 封装库与使用方法示例
Feb 06 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 遍历显示文件夹下所有目录、所有文件的函数,没有分页的代码
2008/11/14 PHP
phpphp图片采集后按原路径保存图片示例
2014/02/18 PHP
php ImageMagick windows下安装教程
2015/01/26 PHP
CI框架实现框架前后端分离的方法详解
2016/12/30 PHP
解析 thinkphp 框架中的部分方法
2017/05/07 PHP
PHP常见的几种攻击方式实例小结
2019/04/29 PHP
DEFER怎么用?
2006/07/01 Javascript
jquery 最简单易用的表单验证插件
2010/02/27 Javascript
腾讯UED 漂亮的提示信息效果代码
2011/09/12 Javascript
前后台交互过程中json格式如何解析以及如何生成
2012/12/26 Javascript
JS在textarea光标处插入文本的小例子
2013/03/22 Javascript
js将当前时间格式转换成时间搓(自写)
2013/09/26 Javascript
js自动生成的元素与页面原有元素发生堆叠的解决方法
2014/09/04 Javascript
原生js实现无限循环轮播图效果
2017/01/20 Javascript
vue.js国际化 vue-i18n插件的使用详解
2017/07/07 Javascript
获取本机IP地址的实例(JavaScript / Node.js)
2017/11/24 Javascript
在 Angular6 中使用 HTTP 请求服务端数据的步骤详解
2018/08/06 Javascript
layui动态渲染生成左侧3级菜单的方法(根据后台返回数据)
2019/09/23 Javascript
Vue使用vue-recoure + http-proxy-middleware + vuex配合promise实现基本的跨域请求封装
2019/10/21 Javascript
JavaScript判断数据类型有几种方法及区别介绍
2020/09/02 Javascript
[10:24]郎朗助力完美“圣”典,天籁交织奏响序曲
2016/12/18 DOTA
[01:35]2018完美盛典章节片——共竞
2018/12/17 DOTA
Python中正则表达式详解
2017/05/17 Python
不可错过的十本Python好书
2017/07/06 Python
梯度下降法介绍及利用Python实现的方法示例
2017/07/12 Python
K-means聚类算法介绍与利用python实现的代码示例
2017/11/13 Python
解决Matplotlib图表不能在Pycharm中显示的问题
2018/05/24 Python
python tkinter实现屏保程序
2019/07/30 Python
Python语言异常处理测试过程解析
2020/01/08 Python
解决Django Haystack全文检索为空的问题
2020/05/19 Python
利用HTML5实现使用按钮控制背景音乐开关
2015/09/21 HTML / CSS
.NET是怎么支持多种语言的
2015/02/24 面试题
SOA的常见陷阱或者误解是什么
2014/10/05 面试题
《长江之歌》教学反思
2014/04/17 职场文书
python 标准库原理与用法详解之os.path篇
2021/10/24 Python
js 实现验证码输入框示例详解
2022/09/23 Javascript