圖片訪問實時處理的實現(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;
}

至此,圖片訪問實時處理也就完成了。其實大部分圖片服務器都需要這樣的功能,而不是事先生成好幾套尺寸的圖片。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM