我在访问时光网、网易云音乐等网站时,发现将它们页面中的一些图片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和php)的更多相关文章

  1. Nginx中防盗链(下载防盗链和图片防盗链)及图片访问地址操作记录

    日常运维工作中,设置防盗链的需求会经常碰到,这也是优化网站的一个必要措施.今天在此介绍Nginx中设置下载防盗链和图片防盗链的操作~ 一.Nginx中下载防盗链的操作记录对于一些站点上的下载操作,有很 ...

  2. UEditor动态添加图片访问路径前缀

    在使用UEditor上传图片时发现上传图片后在编辑器中不能显示上传的图片,在这里是需要在jsp/config.json中设置图片访问路径前缀,即项目的根路径,在config.json只能填写字符串的配 ...

  3. nginx代理图片访问

    nginx代理图片访问 首先配置nginx的代理物理路径 我的是在E盘下面的image 1 #图片的代理 2 server { 3 listen 80; 4 #配置访问的域名 5 server_nam ...

  4. SpringMVC静态文件(图片)访问+js访问 简单小例子

    项目文件布局: web.xml文件: <?xml version="1.0" encoding="UTF-8"?> <web-app vers ...

  5. 使用Nginx做图片服务器时候,配置之后图片访问一直是 404问题解决

    我的错误配置是: 服务器文件根地址: 想通过浏览器输入这个地址访问到图片: 但是会发现文件找不到会一直404,原因是根路径配置错误,来看下root路径原理: root 配置的意思是,会在root配置的 ...

  6. nginx 图片访问404 (使用location中使用 root,alias的区别)

    问题描述: 在/data/code_img/文件下有很多验证码图片,想将他们展示出来 希望通过 http://127.0.0.1/img/1.png 这种形式访问到对应图片,刚开始nginx中配置如下 ...

  7. nginx配置多个图片访问路径

    需求:vue项目打包的时候 会将项目中的一些图片打包到/dist/static/images下,但是有时候会有一些很大的图片,需要单独存放至别的文件夹比如/home/di-img下,不能被打倒包内.部 ...

  8. 公网IP映射修改后,原先的图片访问却不行了

    描述:www与img在一个公网的nginx下时,www访问img没问题   ip:*.*.*.26 www与jimg同样还在同一组nginx,改另一个公网IP映射进来的时候,却访问不了  ip:*.* ...

  9. 不常见偏门的Bug,Spring Boot IDEA 静态资源 图片访问404,初学者之殇

    用过Idea朋友都知道,它有一个非常让人喜欢的功能就是:打算在某个a目录下创建一个hello.class文件,那么你仅需要右键点击New-Java Class- 然后输入名字:a.hello 即可. ...

随机推荐

  1. 关于不断刷新界面jsp+ajax

    jsp主要就是用之前的jsonArray读取 ajax可以设置个定时器,然后设置的方法,至于方法是今天学习到的 function ajax(method,data,url,success){ var ...

  2. 磁带机Media is unrecognized

    早晨检查磁带备份作业时,发现有个驱动的作业一直处于"Queue"状态,检查发现驱动有磁带,在Alert里面发现出现下面"Media is unrecognized&quo ...

  3. Cacti的基本使用

    对于Cacti是通过snmpget来获取数据,使用 RRDtool绘画图形,用snmp服务获取数据,然后用rrdtool储存和更新数据,那么就可以简单理解为Cacti就是RRDTool的一个web图形 ...

  4. 分类-Category

    1.基本用途 如何在不改变原来类模型的前提下,给类扩充一些方法?有2种方式 继承 分类(Category) 2.格式 分类的声明 @interface 类名 (分类名称) // 方法声明 @end 分 ...

  5. Oracle Bills of Material and Engineering Application Program Interface (APIs)

    In this Document Goal   Solution   1. Sample Notes for BOM APIs   2. Datatypes used in these APIs   ...

  6. Github-Client(ANDROID)开源之旅(四) ------ 简介Roboguice

    Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC),Guice非常小而且快.Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数 ...

  7. Java中Redis简单入门

    Redis是一个开源的,先进的 key-value 存储可用于构建高性能,可扩展的 Web 应用程序的解决方案. Redis官方网网站是:http://www.redis.io/,如下: Redis ...

  8. jQuery提示parsererror错误解决办法

    jquery来处理ajax,用到了json.但是很诧异,jquery的ajax回调时一直调用了error函数(一直提示parsererror异常),success函数一次没执行过 $.ajax({ t ...

  9. Python学习笔记 - ifelifelse-forin-while

    if elif else #!/usr/bin/env python3 # -*- coding: utf-8 -*- age = 20 if age >= 18: print('your ag ...

  10. 不裸缩点》。。。POJ2186受欢迎的牛

    不裸缩点>...POJ2186受欢迎的牛 :first-child { margin-top: 0; } blockquote > :last-child { margin-bottom: ...