nodejs和php实现图片访问实时处理
我在访问时光网、网易云音乐等网站时,发现将它们页面中的一些图片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,'!')
.stream(function(err,stdout,stderr){
if(err){
console.log(err);
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功能
首先我们得开启Apacherewrite模块功能,去掉配置文件http.conf中LoadModulerewrite_modulemodules/mod_rewrite.so前面的注释,然后设置Directory块下AllowOverrideAll,可能有多处,接着重启Apache服务。
配置.htaccess文件
在DocumentRoot目录下,新建.htaccess文件,如果创建不了,可以先创建一个文本,然后另存为,在弹出的对话框文件名处填写".htaccess"即可。之后,编写URL重写规则,如下所示:
RewriteEngineon
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版逻辑一致,代码如下:
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);
if(file_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;
}
至此,图片访问实时处理也就完成了。其实大部分图片服务器都需要这样的功能,而不是事先生成好几套尺寸的图片。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。