nodejs构建定时发微博工具,其中几个库的用法
by admin
at 2012-08-15 15:12:01
original http://item.feedsky.com/~feedsky/helloJavaScript/~8514355/692109216/6618683/1/item.html
nodejs构建定时发微博工具,其中几个库的用法
免责声明:本文并非介绍构建成熟系统,只是实现功能,谨慎用于生产环境。
用到的外部库:
express
介绍:一个web框架,提供构建各种web页面的能力。
安装:npm install express
mysql
介绍:在nodejs中操作mysql数据库的库。
地址:https://github.com/felixge/node-mysql/
安装:npm install mysql
consolidate
介绍:将主流模板引擎集合以便在express中使用。
地址:https://github.com/visionmedia/consolidate.js
安装:npm install consolidate
介绍:一个微博库,支持国内各大微博平台,不过这里只用到了新浪。之所以选用这个而没有选中node-weibo-oauth库,因为它不支持发送图片,慎用。
地址:https://github.com/fengmk2/node-weibo
安装:npm install weibo
运行原理
定时发微博,功能其实很简单,一部分是用户的操作界面,可以设定新的计划或者删除某条计划。一部分是后台,定时遍历数据库中的计划,将到时的计划拿出来放到发送队列。然后再定时检查发送队列,将队列内容按一定时间间隔挨个发送。
数据库中有两个表,
一个 wb_info 是用来存储用户的consumer key 和consumer secret的,以用户id为索引。
另一个 queque 用来存储计划队列,以用户id跟第一个表关联。
这样只要定时检查queque表,将信息拿出来跟当前时间做对比,如果需要发送,送到发送队列中。
然后定时检查发送队列,如果有需要发送的计划,则根据其用户id从wb_info中取出用户的consumer key和consumer secret,然后用这二者把计划信息发送到微博,并从queque表删除此条计划。
几个库的使用
1.weibo库
每个库都有很多用法和功能,这里只列本应用用到的功能。
var weibo = require('weibo'); //应用的新浪app信息 var sinaApp = { key : '*******', secret : '********', blogType: 'tsina' } //初始化weibo对象。 weibo.init(sinaApp.blogType, sinaApp.key, sinaApp.secret);
对于绑定微博等功能,weibo提供了一个中间件的东西。说实话我不太懂,只是的确是这么用的。
//weibo中间件,这样,新浪微博的绑定地址就是 /login?type=weibo。app是expess的一个实例 app.use(weibo.oauth({ loginPath: '/login', logoutPath: '/logout', blogtypeField: 'type' // callbackPath:"/oauth" }));
在浏览器中使用/login?type=weibo 访问之后走完接下来的流程,页面会默认调回根url / 用户的绑定信息写在req.session.oauthUser中。
//首页的代码 app.get('/', function(req, res){ var user = req.session.oauthUser if(user){ //如果认证成功(session里有用户信息) console.log("oauth success!") //将用户id和用户名存储到cookie,下次无需认证直接可以使用。 res.cookie("userid", user.id); res.cookie("username", user.name); //将用户的consumerkey和consumersecret存储到数据库,在后台可以直接用这两个信息发送微博,无需用户参与。 ******** //认证成功跳转到oauth页面 res.redirect('oauth'); }else{ res.render('index.html'); } });
这时候你可以在浏览器端做一些跟微博api的交互,例如:
//官方的例子 weibo.public_timeline({ user: { blogType: 'tsina' } }, function (err, statuses) { if (err) { console.error(error); } else { console.log(statuses); } });
这段代码之所以可以运行是因为库会自动根据session中信息构建发送请求。
如果你的代码不是浏览器触发的,二是服务器自己触发的,这时候根本没有session这个东西。就需要单独使用consumer key 和consumer secret来发送请求。
//send a new weibo weibo.update({ user: { blogType: 'tsina', oauth_token_key:'****', //consumer key oauth_token_secret:'*******',//consumer secret authtype: 'oauth' }, status:'**********' // the content to send }, function (err, statuses) { if (err) { console.error(err); } else { console.log("update weibo success") } });
express 和 mustache
express的基本用法网上很多,就不多说鸟。
mustache是一个轻逻辑的小清新模板,使用起来比较简单。因为二者对接起来比较复杂,而且网上的文章大多都过时了,对新版的express来说都不太适用。
consolidate库将常用的模板引擎都做了封装。这里使用它来做中间介绍人。使得把mustache引入express变得很简单,只许一句话,如下:
//设置模板引擎为mustache,这里使用了consolidate库 var cons = require('consolidate') app.engine("html", cons.mustache); //设置模板路径 app.set('views', __dirname + '/views'); app.set('view engine', 'html'); app.set('view options', { layout: false })
模板文件都放在views里面。渲染页面的操作如下。
//中间页面,提醒用户认证成功 app.get('/oauth', function(req, res){ res.render('oauth.html',{data:{}}); });
关于mustache的入门,见我的一篇文章:http://www.html-js.com/?p=1357
mysql
这个库的使用方法就很普通了,没有什么特别多的内容。
var Client = require('mysql').Client var client = new Client(); client.user = sql_username; client.password =sql_pwd; client.query('USE tp_wb'); //这种用法mysql库会帮你自动转义字符,防止xss攻击 client.query( 'INSERT INTO wb_queue '+ 'SET wb_username= ?,wb_id = ?, pic = ?, send_time = ? ,content=?', [req.cookies.username,req.cookies.userid,req.target_path , req.time,req.body.wb_content]); client.end();
静态文件服务
参考这篇文章:http://www.infoq.com/cn/news/2011/11/tyq-nodejs-static-file-server
先设置express的上传文件临时文件夹:
//设置文件上传临时文件夹 app.use(express.bodyParser({ uploadDir:'./uploads' }));
下面是对接到的images*的请求做处理:
//静态图片服务 app.get("/images/*",function(req,res){ var mime= { "css": "text/css", "gif": "image/gif", "html": "text/html", "ico": "image/x-icon", "jpeg": "image/jpeg", "jpg": "image/jpeg", "js": "text/javascript", "json": "application/json", "pdf": "application/pdf", "png": "image/png", "svg": "image/svg+xml", "swf": "application/x-shockwave-flash", "tiff": "image/tiff", "txt": "text/plain", "wav": "audio/x-wav", "wma": "audio/x-ms-wma", "wmv": "video/x-ms-wmv", "xml": "text/xml" }; var realPath = "."+url.parse(req.url).pathname; var ext = path.extname(realPath); ext = ext ? ext.slice(1) : 'unknown'; var contentType = mime[ext] || "text/plain"; path.exists(realPath, function (exists) { if (!exists) { console.log("404 request to"+realPath) res.writeHead(404, { 'Content-Type': contentType }); res.write("This request URL " + realPath + " was not found on this server."); res.end(); } else { fs.readFile(realPath, "binary", function (err, file) { if (err) { console.log(err) res.writeHead(500, { 'Content-Type': contentType }); res.end(err); } else { res.writeHead(200, { 'Content-Type': contentType }); res.write(file, "binary"); res.end(); } }); } }); })
图片上传
表单提交的信息在express中一般存储在req.body中,但是如果有file表单,则文件的信息则会存储到req.files中。
//list页面post处理 app.post('/list', function(req, res) { //获得图片文件的临时路径 var tmp_path = req.files['wb_pic'].path; var type=req.files['wb_pic'].type //如果存在图片 if(req.files['wb_pic'].size>0){ if(req.files['wb_pic'].size>5000000){ req.session.list_error="图片大小超过5M,提交失败!" req.method = 'get'; res.redirect('/list'); return; }else if(!(type=="image/png"||type=="image/jpg"||type=="image/jpeg"||type=="image/gif")){ req.session.list_error="图片格式不是png,jpg,gif,提交失败!" req.method = 'get'; res.redirect('/list'); return; }else{ req.session.list_error="" } // 指定文件上传后的目录 var target_path = './images/'+(new Date().getTime()) +"-"+parseInt(Math.random()*100000000)+"-"+ req.files['wb_pic'].name; // 移动文件 fs.rename(tmp_path, target_path, function(err) { if (err) throw err; // 删除临时文件夹文件, fs.unlink(tmp_path, function() { if (err) throw err; console.log('File uploaded to: ' + target_path + ' - ' + req.files['wb_pic'].size + ' bytes'); ********** }); }); }else{ //没有图片的时候 ******** } });