为什么我们的业务适合用Node?

本文从业务场景来谈谈为什么选择Node,以及前端写后端代码需要补足的短板。

这些日子一直在做Node方面的尝试,或多或少会收到周围的异样的目光甚至背后的质疑,于是促使我好好思考为什么我在做Node。网上搜下「为什么要用Node」,找到的文章多数是介绍Node多么多么牛逼,无非是从Node本身特性来说,比如:并发、事件驱动、非阻塞I/O、单线程、流、社区生态……诸如此类,很少谈业务场景。
我是「实用主义」者,说过:脱离业务场景谈架构都是耍流氓。因为个人是从一线业务做起的,经过几年对业务的思考,我觉得可以从业务场景来说说为什么我们的业务更适合用Node。

从业务场景说起

现在我们的业务模块化越来越普遍,很少有业务比较纯粹只有链接一个数据库就可以搞定,往往前台业务后面会有N多的API服务做支撑。比如:下面两种情况在我们实际开发中经常遇见:

  1. 某个页面需要的数据来自两个以上接口,而两个接口来自不同的团队/部门,比如:用户信息来自账号部门,而UGC数据来自业务部门
  2. 某个页面存在接口依赖,需要先调用接口A,然后根据接口A数据调取接口B,比如:个性化推荐,往往需要根据某些维度请求推荐系统拿到推荐数据的ID,至于内容,需要拿ID根据页面需要去获取具体元数据

上面两种情况,站在后台开发的角度来看,我们业务模块要分开要独立,而站在前端的角度来看,这些数据都是一个页面需要的,前端希望是一个接口给我返回。这是一个开始。。

当然后台开发,比如PHP也有并发请求的解决方案,好(上)心的后台工程师,会帮助在后台统一合并请求处理成一份数据或者接口,然后扔给页面使用。比如在实际开发中,我们的前端会写(并且维护)一个Template.class.php(我敢说我们80%的后台工程师都没看过这个代码。。),在View层使用,然后在Action当中将数据传给View层做渲染,下面的代码:

$this->render('xxx/xx.tpl', $tplData);

这样增加的沟通成本,降低了开发效率。为了一个页面,需要前端根据页面想要的数据,和后台沟通页面的数据格式,然后后台工程师找他们后面的API模块要数据、处理数据。这个过程中会有一些「灰色地带」,不好明确谁做更合适,完全靠自觉。

往往开发的时候会想各种方法来解耦,比如:引入后台模板(smarty之类),然后约定数据格式,前端根据数据格式来写Mock接口,写后台模板的前端就叫「大前端」;再Low一点的团队,会采取前端做好页面扔给后台工程师「套页面」,比如:PHP代码写HTML,各种<?php echo xxx;?>,代码很不友好,后台工程师幸福感也急剧下降。

还有一种做法是,干脆后台沦为「代理服务器」,收到请求我转给后面的API,拿到数据我返回给前端页面,做成可以「跨域」的接口,所以就成了好多webapp。

另外,站在后台工程师的个人发展来看,可能他们觉得:这些「包接口」的重复性工作,跟自己的晋升和技术发展又有毛线关系呢?

说道这里,肯定有人心里在嘀咕:这是你们大公司才有的问题,我们小公司不会有这样的问题!那我下面再从技术方面来说。

用Node抓站(一):怎么写出自己满意的代码

如果只写怎么抓取网页,肯定会被吐槽太水,满足不了读者的逼格要求,所以本文会通过不断的审视代码,做到令自己满意(撸码也要不断迸发新想法!

本文目标:抓取什么值得买网站国内优惠的最新商品,并且作为对象输出出来,方便后续入库等操作

抓取常用到的npm模块

本文就介绍两个:requestcheerio,另外lodash是个工具库,不做介绍,后面篇幅会继续介绍其他用到的npm库。

  • request:是一个http请求库,封装了很多常用的配置,而且也有promise版本(还有next版本。
  • cheerio:是一个类似jQuery的库,可以将html String转成类似jQ的对象,增加jQ的操作方法(实际是htmlparser2

request 示例

var request = require('request');
request('http://www.smzdm.com/youhui/', (err, req)=>{
  if(!err){
    console.log(Object.keys(req))
  }
})

通过上面的代码就看到req实际是个response对象,包括headersstatusCodebody 等,我们用body就是网站的html内容

键">快捷键

版本库地址

more >>

基于express+socket.io的nodejs聊天室

前几天晚上边看水浒边写的nodejs的聊天室,前面说了,放假之前要把近日学习nodejs的所有心得整理下,今天就是30号鸟~撒欢~,最后放这个聊天室出来给大家作为学习nodejs的参考示例,希望对大家有用。

感谢:cnodejs群里的老雷,及其微博上的基友们!顺祝大家长假快乐,顺祝自己明天动车不出轨,顺祝明年不再过节,感慨多了……

特点

聊天室主要功能及其特点:

  1. 采用nodejs(屁话)
  2. express框架,jade做模板
  3. socket.io做前后端的websocket通信
  4. 支持session
  5. 支持@私信功能
    废话不多说了,注意点,基本前面的文章都提到了,下面罗列下:
    配置nodejs.exe的windows目录结构
    安装express及配置app.js文件
    使用socket.io和node.js搭建websocket应用
    在Express和Socket.IO中使用session

nodejs聊天室下载地址

基于express+socket.io的聊天室

聊天室服务器端js代码

在Express和Socket.IO中使用session

在nodejs项目中对于一些认证需要用到session,例如我写的nodejs 聊天室的demo,就是通过session实现的认证。当存在session,直接进入聊天室,而不会重新登录。

在网上也找到不少关于Express框架中的session调用方法,可是发现真正能用的不是很多,今天根据聊天室的制作过程,整理下Express和socket.IO中使用session的具体方法。

Express的session是通过cookie实现的,用到了connect中的两个module:parseCookie和MemoryStore,前者是用来解析cookie,后者用来存储sesion。

引入所需module

Express框架中使用session必须先引入上面的两个模块,例如下面的代码:

var parseCookie = require('connect').utils.parseCookie,
    MemoryStore = require('connect/middleware/session/memory');
//建立一个memory store的实例
var storeMemory = new MemoryStore({
        reapInterval: 60000 * 10
    });

Express中app的配置

在app需要添加如下的配置:

app.configure(function(){
    app.use(express.bodyParser());//解析post
    app.use(express.cookieParser());//解析cookie
    //设置session
    app.use(express.session({
        secret: 'wyq',
        store:storeMemory
    }));
});

在请求中使用session

在请求中我们可以使用request.session来调用session,例如下面的代码:

app.get('/',function(req,res){
    //使用request.session来判断是否登录
    if( req.session.name && req.session.name!==''){
        //需要判断下是否已经登录
        res.redirect('/chat');
    }else{
        //读取登录页面,要求登录
        var realpath = __dirname + '/views/' + url.parse('login.html').pathname;
        var txt = fs.readFileSync(realpath);
        res.end(txt);
    }
});

websocket通信中使用session

在nodejs项目中,我们常常使用websockt来实现通信,所以websocket中也需要通过session来认证用户。本例使用socket.io来举例实现nodejs中websocket通信session的认证。关于socket.io的使用参考文章《使用socket.io和node.js搭建websocket应用

上面代码中引入了解析cookie的parseCookie,所以session是通过cookie来解析的。首先我们建立了socket的监听之后需要对监听到的头文件处理,解析出来cookie中的session。例如下面的代码:

var io = sio.listen(app);
//设置session
io.set('authorization', function(handshakeData, callback){
    // 通过客户端的cookie字符串来获取其session数据
    handshakeData.cookie = parseCookie(handshakeData.headers.cookie)
    var connect_sid = handshakeData.cookie['connect.sid'];
    if (connect_sid) {
        storeMemory.get(connect_sid, function(error, session){
            if (error) {
                // if we cannot grab a session, turn down the connection
                callback(error.message, false);
            }
            else {
                // save the session data and accept the connection
                handshakeData.session = session;
                callback(null, true);
            }
        });
    }
    else {
        callback('nosession');
    }
});

使用socket.io和node.js搭建websocket应用

websocket是HTML5的一种新的通信协议,它是实现了浏览器与服务器的双向通讯。在 WebSocket API 中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
关于websocket的更多信息,请移步维基百科

使用WebSocket

在客户端使用websocket需要创建WebSocket对象,通过提供的open、send、message、close等方法实现创建、发送、监听信息、关闭连接。例如下面的代码:

if('WebSocket' in window){
    // 创建websocket实例
    var socket = new WebSocket('ws://localhost:8080');
    //打开
    socket.onopen = function(event) {
      // 发送
      socket.send('I am the client and I\'m listening!');
      // 监听
      socket.onmessage = function(event) {
        console.log('Client received a message',event);
      };
      // 关闭监听
      socket.onclose = function(event) {
        console.log('Client notified socket has closed',event);
      };
      // 关闭
      //socket.close()
    };
}else{
    alert('本浏览器不支持WebSocket哦~');
}

现在chrome、firefox等浏览器都已经支持了websocket,而IE却没有。下面我们来简单说说服务器端对websocket的支持。

服务器端支持websocket的语言不少,而且都有相关的开源项目,例如php的phpwebsockets:http://code.google.com/p/phpwebsockets/,java的jWebsocket:http://jwebsocket.org/
更多的信息可以浏览这篇文章:Start Using HTML5 WebSockets Today

socket.io

socket.IO是一个websocket库,包括了客户端的js和服务器端的nodejs。官方地址:http://socket.io

客户端使用socket.io

去github clone socket.io的最新版本,或者直接饮用使用socket.io的CDN服务:

<script src="http://cdn.socket.io/stable/socket.io.js"></script>

下面可以创建使用socket.io库来创建客户端js代码了:

var socket = io.connect('http://localhost');
socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
});

socket.on是监听,收到服务器端发来的news的内容,则运行function,其中data就是请求回来的数据,socket.emit是发送消息给服务器端的方法。

使用socket.io和nodejs搭建websocket服务器端

socket.io不仅可以搭建客户端的websocket服务,而且支持nodejs服务器端的websocket。

nodejs安装socket.io

使用node插件管理包,运行下面的命令就可以安装成功socket.io

npm install socket.io

没有npm的或者windows用户可以使用github下载socket.io并且放入到node_modules文件夹中,具体配置可以参考文章:《nodejs教程:配置nodejs.exe的windows目录结构》

nodejs建立socket.io服务

通过nodejs的http模块就可以方便的搭建websocket服务器环境,例如下面的代码:

// 引入需要的模块:http和socket.io
var http = require('http'), io = require('socket.io');
//创建server
var server = http.createServer(function(req, res){
  // Send HTML headers and message
  res.writeHead(200,{ 'Content-Type': 'text/html' });
  res.end('

# Hello Socket Lover!
');
});
//端口8000
server.listen(8080);
//创建socket
var socket = io.listen(server);
//添加连接监听
socket.on('connection', function(client){
    //连接成功则执行下面的监听
    client.on('message',function(event){
        console.log('Received message from client!',event);
    });
    //断开连接callback
    client.on('disconnect',function(){
        console.log('Server has disconnected');
    });
});

nodejs教程:安装express及配置app.js文件

express.js是nodejs的一个MVC开发框架,并且支持jade等多种模板。下面简单来说说express的安装和app.js文件的配置,然后在今后的教程中一步一步使用express.js搭建个聊天室。

安装express.js

如果你安装了npm,安装变得很简单,只需要在终端中运行下面的代码即可:

npm install express -gd
-g代表安装到NODE_PATH的lib里面,而-d代表把相依性套件也一起安装。如果沒有-g的话会安装目前所在的目录(会建立一个node_modules的文件夹),你可以透过以下指令来比较两者的不同:

npm list -g
npm list

如果没有npm,那么我可以使用github来git下来最新的express。
好了,现在你可以通过express testapp来建立express实例。以下是示例:

cd ~
express testapp
cd testapp
node app.js
这样就建立了一个testapp的nodejs应用,而app.js是默认的应用主js。下面来详细的说说app.js中的各项配置。

引入模块

var express = require('express');
 var app = module.exports = express.createServer();

require()是node.js提供的函数,可以让你引入其他模块以调用模块的函数和变量,默认下node.js会在$NODE_PATH和目前js所在目录下的node_modules文件夹下去寻找模块。require也可以用来载入自己写的模块哦~这样涉及到node.js的模块机制,后面有机会就在介绍。

第二行的express.createServer()就是在建立server,而中间的module.exports也是涉及到node.js的模块机制,以后再说。

express的app.js的详细配置说明

express.js继承自connect模块,所以如果你的node_modules文件夹下没有connect模块也是不行的。

设置views路径和模板

我们再来看下面两行:

app.set('views', __dirname + '/views');
app.set('view engine', 'jade');