使用nodejs搭建图片服务器(一)
背景
当我们开发一个Web项目的时候,为了将图片管理与web服务分离开,通常都会搭建一个图片服务器。
之所以选择nodejs是因为使用nodejs来搭建web项目相当简单而且快速,虽然这个图片服务器很简单,也有很多人会认为使用nodejs来当图片服务器不合适,但是当我们的应用没有达到非常大的程度的情况下,其实nodejs还是够用的。
会使用到的工具如下:
- nodejs
- express(nodejs mvc框架)
- body-parser(express middleware)
- gm(nodejs中用来处理图片的)
- uuid(nodejs中用于生成uuid)
- underscore(nodejs数据处理库)
- ImageMagick(gm会调用该程序处理图片)
那么接下来就来尝试实现这个简易的图片服务器吧, ^_^
搭建项目
首先要使用express来搭建项目,由于图片服务器的功能相对简单,只有2个功能:1、获取图片资源 2、上传图片,因此对应express只需要使用到bodyParser这样的组件,代码大致如下:
//app.js
var app = require('express')();
process.app = app;//方便在其他地方使用app获取配置 require('./config')(__dirname, app);//所有配置
var mode = app.get('mode');
require('./controller/' + mode + 'Controller.js'); var config = app.get(mode);
require('http').createServer(app).listen(config.port, function () {
console.log('%s已经启动,正监听:%s', config.name, config.port);
}); //config.js
var path = require('path'); var OPTIONS = {
targetDir: function (app) {
return path.join(app.get('rootDir'), 'img');
},
read: {
name: '<<图片服务器(读取)>>',
port: 80,
'default': 'default.jpg',
sizeReg: /(\w+)-(\d+)-(\d+)\.(\w+)$/
},
save: {
name: '<<图片服务器(保存)>>',
port: 9990
},
mode: 'read',
contentType: {
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'gif': 'image/gif',
'png': 'image/png'
}
}; module.exports = function (rootDir, app) {
app.set('rootDir', rootDir); var $ = require('underscore');
$.each(OPTIONS, function (v, k) {
app.set(k, typeof v === 'function' ? v(app) : v);
}); app.use(require('body-parser')())
};
上面独立出了config.js是为了将所有的配置放在一起方便维护,其次配置中的mode是为了区分当前是一个读取还是存储服务器。
获取图片
这是图片服务器的其中一个功能,用户根据url获取图片服务器内存储的图片,当后台接收这个请求后,首先判断图片上会否存在,如果存在则返回对应的图片否则返回默认的图片,大致代码如下:
var path = require('path');
var fs = require('fs');
var gm = require('gm').subClass({ imageMagick: true });//默认的情况下 gm使用的是另外一个图片处理程序
var app = process.app;
var config = app.get('read');
var targetDir = app.get('targetDir');
app.get('/:filename', function (req, res) {
var filePath = path.join(targetDir, req.params.filename);
fs.exists(filePath, function (exists) {
res.sendfile(exists ? filePath : path.join(targetDir, config.default));
});
});
使用以上的代码便可以对图片进行读取了,但是只能对targetDir目录下的文件进行读取且没有对文件类型进行判断,对文件类型的判断比较简单只要在方法执行之前对文件扩展名进行判断即可,至于增加了文件夹结构的话,跟直接从targetDir目录下读取是差不多的流程,稍微调整一下代码:
var contentTypes = app.get('contentType');
app.get('/:filename', function (req, res) {
sendFile([], req.params.filename, res);
});
app.get('/:folder/:filename', function (req, res) {
sendFile([req.params.folder], req.params.filename, res);
});
app.get('/:folder1/:folder2/:name', function (req, res) {
sendFile([req.params.folder1, req.params.folder2], req.params.filename, res);
});
function sendFile(folders, filename, res) {
var ext = path.extname(filename).substr(1);
if (!contentTypes[ext])
return res.sendfile(getFilePath());
folders.push(filename);
var filePath = getFilePath(path.join.apply(path, folders));
fs.exists(filePath, function (exists) {
res.sendfile(exists ? filePath : getFilePath());
});
}
function getFilePath(filename) {
return path.join(app.get('targetDir'), filename || config.default);
}
接下来假设一个场景,如果上传了一张800*600的图片,但是在页面上显示的时候,也许我只想显示一张200*150的缩略图,这时候gm就该登场了,我们可以使用gm来为800*600的图片临时生成一张200*150的图片,并以buffer的形式回传给客户端,大致代码如下:
//判断请求图片是否存在
if (exists)
return res.sendfile(filePath); var groups = filename.match(config.sizeReg);
if (!groups)
return res.sendfile(getFilePath()); folders[len] = groups[1] + "." + groups[4];
filePath = getFilePath(path.join.apply(path, folders));
var width = parseInt(groups[2]);
var height = parseInt(groups[3]);
//判断原始图是否存在
fs.exists(filePath, function (exists) {
if (!exists)
filePath = getFilePath(); var gm = gm(filePath);
if (width > 0 && height > 0)
gm.resize(width, height);
gm.toBuffer(function (err, buffer) {
if (err)
return res.sendfile(getFilePath()); res.set('Content-Type', contentTypes[ext]);
res.send(buffer);
});
});
上传图片
由于图片服务器只提供最简单的功能,支持文件上传,但是并不会对上传的文件制作水印以及其他的处理,也不会将此功能开放到外网,因此图片上传服务器是在内网的,只能从web服务器那边处理图片以后上传到图片服务器,图片服务器对其进行存储并返回存储后的图片路径,大致代码如下:
var buf = require('buffer');
var fs = require('fs');
var path = require('path');
var util = require('util');
var gm = require('gm').subClass({ imageMagick: true });
var uuid = require('uuid');
var app = process.app;
var contentTypes = app.get('contentType');
/*
请求包含如下参数:
@ext 图片扩展名
@buffer 图片buffer数据
@folder 文件夹,格式:/aa/bb
*/
app.post('/', function (req, res) {
var ext = req.body.ext;
var buffer = req.body.buffer;
if (!(ext && buffer && contentTypes[ext]))
return res.json({ success: false });
var pathArgs = req.body.folder.replace(/\n/g, '');
if (pathArgs)
pathArgs = pathArgs.substr(1).split('/');
else
pathArgs = [''];
createDir(pathArgs);
pathArgs.push('');
var filePath = createPath(pathArgs, ext);
gm(new buf.Buffer(JSON.parse(buffer))).write(filePath, function (err) {
if (err)
return res.json({ success: false });
res.json({ success: true, data: util.format('\\%s.%s', pathArgs.join('\\'), ext) });
});
});
function createDir(pathArgs) {
if (pathArgs[0]) {
var dir = path.join(app.get('targetDir'), path.join.apply(path, pathArgs));
var exists = fs.existsSync(dir);
if (!exists)
fs.mkdirSync(dir);
}
}
function createPath(pathArgs, ext) {
var args = [app.get('targetDir')];
pathArgs[pathArgs.length - 1] = uuid.v1().replace(/-/g, '');
args.push.apply(args, pathArgs);
var filePath = path.join.apply(path, args) + '.' + ext;
return fs.existsSync(filePath) ? createPath(pathArgs, ext) : filePath;
}
结尾
到这里我们就完成了一个nodejs版本的图片服务器了,因为尽可能将不需要的功能剥离到了其他的项目中去,因此图片服务器的功能就变得很简单、单一了。
对于图片获取服务器生成临时大小的文件,可以先缓存起来,并结合leasing模式进行管理,频繁使用的情况下可以翻倍增加它的租约,到期则直接释放。
而图片存储服务器,如果对于某些应用上传的图片都会生成固定系列大小的情况下, 可以使用gm对原始图进行二次处理,根据规则批量生成各种大小的图,至于图片的名字可以采用一些规则,这样返回的话,依然是存储后的原始图,而且格式则可以通过获取服务器获取,无需再进行缓存了。
由于大部分的代码已经提供了,请不要再跟我要什么源码之类的哦,大家可以自己尝试搭建一下,今天就到这里了,如果有什么问题请告知我,谢谢各位。
使用nodejs搭建图片服务器(一)的更多相关文章
- Nginx+Nodejs搭建图片服务器
图片上传请求由Node处理,图片访问请求由Nginx处理. 1.Nginx配置 #user nobody; worker_processes 1; #error_log logs/error.log; ...
- NodeJS搭建HTTPS服务器
[NodeJS搭建HTTPS服务器] http://cnodejs.org/topic/54745ac22804a0997d38b32d
- 使用Tomcat搭建图片服务器,使图片能够用链接访问
在后台和前端交互时,遇到了后台存储的图片,前端根据地址无法访问,使用Tomcat搭建图片服务器 1.找到tomcat下的server.xml文件 2.配置文件下加入service节点 <!--为 ...
- nginx+ftp搭建图片服务器(Windows Server服务器环境下)
几种图片服务器的对比 1.直接使用ftp服务器,访问图片路径为 ftp://账户:密码@192.168.0.106/31275-105.jpg 不采用这种方式,不安全容易暴露ftp账户信息 2.直接使 ...
- Nginx 搭建图片服务器
Nginx 搭建图片服务器 本章内容通过Nginx 和 FTP 搭建图片服务器.在学习本章内容前,请确保您的Linux 系统已经安装了Nginx和Vsftpd. Nginx 安装:http://www ...
- linux上搭建图片服务器
之前写过一个搭建图片服务器的随笔:https://www.cnblogs.com/xujingyang/p/7163290.html ,现在回头看看,我去,感觉写的好乱,现在再整一个吧.o(╯□╰ ...
- ueditor搭建图片服务器
最近用使用富文本编辑器,之前一直使用kindeditor和eWebEditor来着,有同事给推荐说使用百度推出的Ueditor,所以咯,自己新项目就将它引进来了,这里说一下心得, 说实话,Uedito ...
- Nginx搭建图片服务器
Nginx搭建图片服务器 标签(空格分隔): linux,nginx Nginx常用命令 ./nginx 启动 ./nginx -s reload 重载配置文件 ./nginx -s stop|sta ...
- nginx 搭建图片服务器(windows 下,linux 下原理应该一样)
作者的心声:很多知道的.用过的东西,不写下来,下次还要百度查询,浪费时间和精力,故本次写下学习笔记,方便下次查阅. 题外话:如有读者通过我这篇博客解决了工作上的难题,可以给个评论,让我一起分享你的喜悦 ...
随机推荐
- .NET读取Office文件内容(word、excel、ppt)
引用命名空间 using Microsoft.Office.Core; using Word = Microsoft.Office.Interop.Word; using Excel = Micros ...
- java防止脚本注入,通过拦截器实现
1:利用action过滤 package com.tsou.comm.servlet; import java.util.Enumeration; import java.util.Map; impo ...
- [推荐]移动H5前端性能优化指南
[推荐]移动H5前端性能优化指南 http://isux.tencent.com/h5-performance.html
- Apache Solr查询语法(转)
查询参数 常用: q - 查询字符串,必须的. fl - 指定返回那些字段内容,用逗号或空格分隔多个. start - 返回第一条记录在完整找到结果中的偏移位置,0开始,一般分页用. rows - 指 ...
- 【地图API】收货地址详解2
上次讲解的方法是: 在地图中心点添加一个标注,每次拖动地图就获取地图中心点,再把标注的位置设置为地图中心点.可参考教程:http://www.cnblogs.com/milkmap/p/6126424 ...
- 鸡和蛋的OO设计
一个题目:用类图表示出鸡和蛋的关系. 第一版: 第二版: 一个鸡可以下N个蛋,一个蛋可以浮出0或者1个鸡. 问题是公鸡不会下单,第三版:
- CentOS6.5下安装Open vSwitch
准备 # yum install openssl-devel redhat-rpm-config kernel-devel -y #yum install kvm libvirt python-vir ...
- Java蛇形数组的简单实现代码
上周五和朋友聊天谈到个蛇形数组的java实现办法,命题是:假设一个二维数组宽w高h,从1开始蛇形输出. int[][] numberMatric = new int[w][h]; 当时午睡过头脑袋不清 ...
- C++矩阵运算库推荐
最近在几个地方都看到有人问C++下用什么矩阵运算库比较好,顺便做了个调查,做一些相关的推荐吧.主要针对稠密矩阵,有时间会再写一个稀疏矩阵的推荐. Armadillo:C++下的Matlab替代品 地址 ...
- 【组合数学+动态规划】在如下8*6的矩阵中,请计算从A移动到B一共有____种走法。要求每次只能向上或向右移动一格,并且不能经过P。
在如下8*6的矩阵中,请计算从A移动到B一共有__种走法.要求每次只能向上或向右移动一格,并且不能经过P. A:456 B:492 C:568 D:626 E:680 F:702 解析: 8*6的矩阵 ...