使用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 下原理应该一样)
作者的心声:很多知道的.用过的东西,不写下来,下次还要百度查询,浪费时间和精力,故本次写下学习笔记,方便下次查阅. 题外话:如有读者通过我这篇博客解决了工作上的难题,可以给个评论,让我一起分享你的喜悦 ...
随机推荐
- Backbone入门——开发第一个Backbone页面
1. 功能描述在新建的html页面中,通过导入的backbone文件搭建一个简单的mvc结构.当用户进入该页时,id号为“divTip”的<div>元素中将显示“hello,backbon ...
- [译]JavaScript中,{}+{}等于多少?
最近,Gary Bernhardt在一个简短的演讲视频“Wat”中指出了一个有趣的JavaScript怪癖:在把对象和数组混合相加时,会得到一些你意想不到的结果.本篇文章会依次讲解这些计算结果是如何得 ...
- avalon实现一个简单的带增删改查的成绩单
自从angular问世,一直就有去了解学习angular,一直想用angular去做一个项目,但无奈,大ng是国外产物,ng1.2版本就只兼容到IE8,1.3后的几个版本提升到IE9,据说NG2.0更 ...
- paip.python连接mysql最佳实践o4
paip.python连接mysql最佳实践o4 python连接mysql 还使用了不少时间...,相比php困难多了..麻烦的.. 而php,就容易的多兰.. python标准库没mysql库,只 ...
- win7给C盘扩容
win7给C盘扩容 需要给C盘在不重装系统的情况下进行扩容.在网上搜索了不少资料,包括使用系统自带的分区工具,PQ等软件,都没有成功.不小心看到了分区助手,使用之,迅速的解决了问题,而且解决的非常完美 ...
- 使用Webpack和Babel来搭建React应用程序
用Webpack(npm install -g webpack)代码打包,Webpack大致需要知道三件事: 1)让Webpack知道应用程序或js文件的根目录 2)让Webpack知道做何种转换 3 ...
- WindowsPhone-GameBoy模拟器开发四--Gameboy显示系统分析
这次说一下GB的显示系统,先从一幅Gb的内存分布图说起,请看图: 图中红色框框起来的部分就是这篇文章关注的部分,这一部分的内存地址从8000-9Fff,共8KB,这一部分是从来存储背景和游戏“精灵”的 ...
- [算法导论]拓扑排序 @ Python
class Graph: def __init__(self): self.V = [] class Vertex: def __init__(self, x): self.key = x self. ...
- Meaningful Use 中与HL7相关的消息及医疗文档
汇总 HL7 消息 入出转消息 ADT A01,A03,A04,A08 免疫消息 VXU V04 电子处方消息 NEWRX Message v8.1 EDIFACT, v8.1 XML, v10.6 ...
- vc 实现打印功能
Visual C++6.0是开发Windows应用程序的强大工具,但是要通过它实现程序的打印功能,一直是初学者的一个难点,经常有朋友询问如何在VC中实现打印功能,他们往往感到在MFC提供的框架内实现这 ...