第八章 构建Web应用
在具体的业务中,我们有如下的这些需求(实际开发中一般用 Express框架,它帮我们做了很多事情),这里以访问 http://127.0.0.1/admin/head/on?sort=-startedAt&role=normal为例来说说一个一个框架所做的事情
- 请求方法的判断(req.method)
- URL的路径解析(用url.parse解析出/admin、/head、/on)
- URL中查询字符串的解析(用querystring模块 解析得到?sort=-startedAt&role=normal)
- Cookie的解析,通过CookieID查询得到Session
- 表单数据的解析
- 处理文件上传
设置缓存来加速网站的打开(比如网站的图标之类的长期不会改变的东西),通过读取request头部中的if-modified-since和if-none-match来判断,具体代码如下
//处理if-modified-since
var http = require('http');
var crypto = require('crypto');
//将文件对应的hash值作为Etag的值
var getHash = function(str){
var shaum = crypto.createHash('sha1');
return shaum.update(str).digest('base64');
}
//这里是伪代码,重要的是理解思路
http.createServer(function (req, res) {
fs.readFile(filename, function(err, file){
var hash = getHash(file);
var noneMatch = req.header['if-none-match'];
if (hash === noneMatch) {
res.writeHead(304,"Not Modified");
res.end();
} else {
res.setHeader("ETag",hash);
res.writeHead(200,"ok");
res.end(file);
}
});
}).listen(8000);
//处理ETag
var http = require('http');
//这里是伪代码,重要的是理解思路
http.createServer(function (req, res) {
if (lastModified === req.headers["if-modified-since"]) {
res.writeHead(304);
res.end();
} else {
fs.readFile(filename, function(err, file){
var lastModified = stat.mtime.toUTCString();
res.setHeader("Last-Modified":lastModified);
res.writeHead(200,"ok");
res.end(file);
});
}
}).listen(8000);
中间件
中间件的设计就是Unix哲学的体现,专注简单,小而美,组合起来发挥强大的力量。(直接拍照片了哈~~)
中间件能简化和隔离基础设施(cookie、session、url解析、req.body中携带的信息)与业务逻辑(courseOpen、userAdd),最终提高开发效率。以connect为例,传递的参数和上下文就是req和res,一个中间件处理完成后,调用next()方法通知下一个中间件进行处理。
模板
模板技术的本质就是在拼接字符串,将hello <%=text%> 变为 hello world,同时内部需要提供转义功能,将能形成HTML标签的字符(&、<、>、”、’)转换为安全的字符(<、>)。
几个步骤如下:
- 语法分析,取出普通字符串和表达式。<%=%>的正则表达式为/<%([\s\S]+?)%>/
- 处理表达式
第九章 进程
Node内置了child-process模块,可以用于创建子进程,有几个CPU就创建几个子进程。子进程中用process.on, process.send进行交互,主进程中用child.on,child.send进行交互.。示意图如下:
IPC
IPC进程间通信(Inter-Process Communication) 。进程间通信的目的是为了让不同的进程能够互相访问资源并进行协调工作。实现进程间通信的技术有很多,如命名管道、匿名管道、socket、信号量、共享内存、消息队列、DomainSocket等。Node中实现IPC通道的是管道(pipe)技术。但此管道非彼管道,在Node中管道是个抽象层面的称呼,具体细节实现由libuv提供,在Windows下由命名管道(named pipe)实现,*nix系统则采用Unix Domain Socket实现。示意图如下:
这边为了解决不同进程监听同一个端口时发生的端口被占用的问题,Node中引入了进程间发送句柄这样的概念。
句柄是一种用来标识资源的引用,它的内部包含了指向对象的文件描述符,所以句柄可以用来标识一个服务器端socket对象、一个客户端socket对象、一个TCP套接字、一个管道。
有了句柄,我们可以做到很不可思议的事情,例如将一个TCP服务器直接发给了子进程。如图所示。
面对访问量特别大的端口,我们可以启动多个进程,让他们监听一个端口,且这种监听是抢占式的(谁先抢到谁上)。实现的抢占式效果如图所示:
原理:
send方法在发送句柄时,其实是把文件描述符发送给子进程,所以子进程可以在创建TCP服务器对象后监听到对应的文件描述符上,从而避免了监听到相同端口时发生的异常,在多个应用监听相同端口时,文件描述符同一时间只能被一个进程使用,这样就形成了抢占式服务。
小结:
以上功能在cluster模块均有实现(果然已经有了现成的*-。-,不过了解一下原理对未来的提升还是有好处的~~)
第十章:测试
不用废话了,直接用mocha~~