美文网首页
node学习笔记(后篇)

node学习笔记(后篇)

作者: ifcode | 来源:发表于2015-04-23 04:57 被阅读709次

    8. TCP服务和socket连接

    开始这部分前,需要先解释一下当初让我困惑许久的TCP/IP、HTTP和socket之间的关系。

    TCP/IP是一组协议栈,从底向上包含网络层、传输层和应用层。IP协议在最底层的网络层,TCP协议在中间的传输层,而HTTP则位于最顶层的应用层。所以HTTP是一个位于应用层的协议,一般用于web服务器和本地浏览器之间的数据传输。

    TCP协议在HTTP协议的下一层,为HTTP提供服务。当浏览器请求web服务器的数据时,会通过TCP建立一条到服务器的连接,数据传输完成后关闭连接。

    socket就不同了,它本身不属于TCP/IP协议栈。它其实是一个TCP/IP编程的接口,主要是为了方便进行网络编程而开发的。

    好了,这几个概念清楚后,让我们来看看node中如何处理TCP和socket。

    在node中建立一个原始的TCP服务需要net模块。使用net.createServer()就可以建立一个简单的TCP服务。createServer接收一个callback为参数,该callback在每次TCP连接的时候都会被调用。

    callback接收一个socket对象作为参数,该对象包含许多关于本次连接的参数。我们可以读取socket中的参数,也可以利用它传递信息给请求方(socket.write()或socket.end())。

    最后还要注意,使用net.createServer()建立服务器之后,还需要使用listen方法来监听某一特定的端口。一个简单的TCP服务器可以写成:

    var net = require('net');
    
    var server = net.createServer(function(socket) {
      socket.end('end of connection');
    });
    server.listen(3000);
    

    9. HTTP服务

    node的http模块也可以建立服务,也就是我们常见的web服务。http.createServer()就可以建立一个http服务,该方法同样接收一个callback作为参数。

    这里callback和net的callback不同,它有两个参数:request和response。我们稍微复习一下http的基本原理:客户端每次发送一个请求(request),服务器对该请求作出响应,响应内容作为response返回给客户端。响应完毕,客户与服务器之间的连接随即关闭。request可以有不同的请求类型,常见的有GET、POST、PUT、DELETE几个。

    现在callback两个参数的意义就很明确了,request用来获取客户端请求的详细信息,在对请求作出相应的处理后,结果通过response返回给客户端。

    下面让我们来看一个简单的例子,一个http服务只接收post请求,将请求的内容转换为大写再返回给客户端。这里要注意request和response都有streaming的概念,内容可以按流输入和输出。为了方便处理,这里使用了一个through2-map模块来传递数据流。

    var http = require('http');
    var map = require('through2-map');
    
    var server = http.createServer(function(req, res) {
      if (req.method != 'POST') {
        return res.end('send me a POST\n');
      }
    
      req.pipe(map(function(chunk) {
        return chunk.toString().toUpperCase();
      })).pipe(res);
    });
    
    server.listen(Number(process.argv[2]));
    

    两个地方需要注意一下:首先是可以直接用request.method来了解请求的类型。另外一个是在listen端口号的时候,使用了Number来将命令行参数转换为数字。

    10. JSON API服务

    JSON API是现在常见的web服务方式。web服务器只提供一组API接口,客户端根据接口请求需要的信息。信息通过JSON的形式在服务器和客户端之间传输。

    node中实现JSON API的方式非常直观。下面让我们来看看不使用框架如何实现简单的JSON API。

    首先,API是通过HTTP的形式实现的,所以必须使用node的http模块。前面说过,API实际上是一组接口,也就是某种形式的路径。客户端根据API发出请求。根据前面说过的关于HTTP服务的知识,我们知道所有客户端的请求信息都包含在request对象中。这个对象除了代表访问类型的method属性外,还有一个很重要的属性url,就是请求的地址(路径)。根据这个路径和其附带的参数,我们就能判断客户端需要的内容了。

    request的url属性是一个对象,包含了客户端发送请求的许多信息。比如客户端发送这样一个请求:

    /api/parsetime?iso=2013-08-10T12:10:15.474Z

    里面包含了请求的地址/api/parsetime,也包含的请求的参数iso=2013-08-10T12:10:15.474Z。手动解析这个对象显然非常麻烦,于是这里又有一个常用的node模块url,它提供了针对url的许多方法,我们这里需要的是url.parse(request.url, true)这个方法来解析url请求。这里的true是为了将参数解析为对象的形式。没有true的话解析结果将会有一个query属性为iso=2013-08-10T12:10:15.474Z;加上true则会将查询参数也解析为一个对象,即类似{query: {iso: '2013-08-10T12:10:15.474Z'}}的形式。

    路径解析出来了,我们就可以简单实现许多框架中的route的概念了。其实route最简单的形式就是一个switch,根据路径执行响应的case来对请求作出响应:

    function route(reqUrl) {
      var parse = url.parse(reqUrl, true);
      var res = {};
      switch (parse.pathname) {
        case '/api/parsetime':
          res = parsetimeIso(parse.query);
          break;
        case '/api/unixtime':
          res = parsetimeUnix(parse.query);
          break;
        default:
          console.error('Unknown route');
      }
    
      return res;
    }
    

    这里我定义了两条route:/api/parsetime和/api/unixtime。他们分别对查询参数调用不同的函数,返回不同的处理结果。

    最后,在将处理结果返回给客户端前还需要做一些处理。既然叫做JSON API服务,返回给客户的自然是JSON对象了。于是需要用到js内置的JSON.stringify()做最后的处理,保证返回JSON对象。

    让我们来看看这个完整的程序吧,程序很简单,只有上面定义的两个API接口,查询参数是一个ISO格式的时间。parsetime接口取出这个时间的小时、分钟和秒。parsetimeUnix则将这个时间转换为unix时间戳。转换结果统一为JSON格式返回给客户:

    var http = require('http');
    var url = require('url');
    
    server = http.createServer(function (req, res) {
      if (req.method != 'GET') return res.error('You should send me a GET\n');
    
      var response = route(req.url);
      var json = JSON.stringify(response);
      res.writeHead(200, {'Content-Type': 'application/json'});
      res.end(json);
    });
    server.listen(process.argv[2]);
    
    function route(reqUrl) {
      var parse = url.parse(reqUrl, true);
      var res = {};
      switch (parse.pathname) {
        case '/api/parsetime':
          res = parsetimeIso(parse.query);
          break;
        case '/api/unixtime':
          res = parsetimeUnix(parse.query);
          break;
        default:
          console.error('Unknown route');
      }
    
      return res;
    }
    
    function parsetimeIso(query) {
      var date = new Date(query.iso);
      return {
        'hour': date.getHours(),
        'minute': date.getMinutes(),
        'second': date.getSeconds()
      };
    }
    
    function parsetimeUnix(query) {
      return {'unixtime': Date.parse(query.iso)};
    }
    

    经过前面的讲解,相信看懂这个程序是没问题了。到这里,我们短暂的node之旅也暂时告一段落的。这个简短的笔记中并未涉及太多高层次的模块和框架,就是为了告诉大家node的本质其实是比较靠底层的。除了做web服务器之外,node也为js打开了系统脚本,TCP服务等一系列领域的大门。相信自己的选择,努力吧少年!世界终将是你们的。

    相关文章

      网友评论

          本文标题:node学习笔记(后篇)

          本文链接:https://www.haomeiwen.com/subject/qfzufttx.html