• 图片访问实时处理的实现(nodejs和php)


    我在访问时光网、网易云音乐等网站时,发现将它们页面中的一些图片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;
    }
    

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

  • 相关阅读:
    css 如何隐藏滚动条
    点击元素之外隐藏
    css3 box-shadow
    video常用功能
    input依次输入密码
    响应式布局基础
    数据库
    面试题
    pandas
    Numpy
  • 原文地址:https://www.cnblogs.com/zmxmumu/p/6252538.html
Copyright © 2020-2023  润新知