Node与express开发

1.初识Express

Express 网站上是这样介绍 Express 的: “精简的、灵活的 Node.js Web 程序框架,为构建单页、多页及混合的 Web 程序提供了一系列健壮的功能特性。 ”这到底是什么意思呢?下面咱们来逐一解读一下。html

精简
这是 Express 最吸引人的特性之一。框架开发者常常会忘掉“少便是多”这一基本原则。Express 的哲学是在你的想法和服务器之间充当薄薄的一层。这并不意味着它不够健壮,或者没有足够的有用特性,而是尽可能少干预你,让你充分表达本身的思想,同时提供一些有用的东西。node

灵活
Express 哲学中的另外一个关键点是可扩展。Express 提供了一个很是精简的框架,你能够根据本身的须要添加 Express 功能中的不一样部分,替换掉不能知足须要的部分。这种作法很新鲜。不少框架把什么都给你了,一行代码还没写,你拥有的就已是一个臃肿、神秘而复杂的项目了。一般,你的第一项任务就是把不须要的功能砍掉,或者替换掉不能知足需求的功能。Express 则采起了大相径庭的方式,让你在须要时才去添加东西。git

Web程序框架
这里须要琢磨一下语义了。什么是 Web 程序?这意味着 Express 就不能作出网站或者网页了吗?不,网站是 Web 程序,网页也是 Web 程序。但 Web 程序的含义不止这些,它还能够向其余 Web 程序提供功能(还有别的) 。通常而言, “程序”是具备功能的,它不止是内容的静态集合(尽管这也是很是简单的 Web 程序) 。尽管如今“程序” (在你的设备本地运行的东西)和“网页” (经过网络为你的设备服务的东西)之间有明显的界限,但这种界限渐渐变得模糊了,这要感谢 PhoneGap 这样的项目,同时也要感谢微软容许 HTML5 像本地应用程序同样在桌面上运行。不难想象,几年以内程序和网站之间的界限将不复存在。程序员

单页Web程序
单页 Web 程序是比较新颖的想法。不像以前的网站,用户每次访问不一样的页面都要发起网络请求,单页 Web 程序把整个网站(或很大一部分)都下载到客户端浏览器上。通过初始下载后,用户访问不一样页面的速度更快了,由于几乎不须要或者只要不多的服务端通讯。单页程序的开发可使用 Angular 或 Ember 等流行框架,Express 跟它们都
配合得很好。github

多页和混合的Web程序
多页 Web 程序是更传统的方式。网站上的每一个页面都是经过向服务器发起单独的请求获得的。这种方式确实比较传统,但这并不意味着它没有优势,或者说单页程序更好。只是如今有更多选择了,你能够决定哪些内容应该做为单页程序提供,哪些应该经过不一样的请求提供。 “混合”说的就是同时使用这两种方式的网站。
若是你仍是很困惑 Express 到底是什么,不用担忧。有时候只管把某些东西拿来用就行了,不用先理解它是什么,本书将教你如何用 Express 开发 Web 程序。web

express官方迁移指南express

2.用Node实现的简单Web服务器

若是你以前曾经作过静态的 HTML 网站,或者有 PHP 或 ASP 背景,可能习惯用 Web 服务器(好比 Apache 或 IIS)提供静态文件服务,以便使用浏览器经过网络查看这些文件。好比说,若是你建立了一个名为 about.html 的文件,并把它放到了恰当的目录下,而后就能够访问 http://localhost/about.html 查看这个文件。根据 Web 服务器的配置,你甚至能够省略 .html,但 URL 和文件名之间的关系很清晰:Web 服务器知道文件在机器的哪一个地方,
并能把它返回给浏览器。
从 localhost 的名字就能看出来,它指的是你所在的机器。这是 IPv4 回环地址 127.0.0.1 或者 IPv6 回环地址 ::1 的经常使用别名。你应该更常见到 127.0.0.1,不过本书中用的是 localhost。若是你用的是远程的机器(好比经过 SSH 访问的) ,记得浏览 localhost 时访问的不是你眼前的那台机器。
Node 所提供的范式跟传统的 Web 服务器不一样:你写的程序就是 Web 服务器。Node 只是给你提供了一个构建 Web 服务器的框架。你可能会说“但我不想写 Web 服务器” 。这是很天然的反应:你想写一个程序,而不是Web 服务器。然而在 Node 里编写 Web 服务器很是简单(甚至只须要几行代码) ,而且你所以取得了对程序的控制权,这是很是值得的。那么咱们开始吧。若是你已经安装了 Node,也已经熟悉了终端,如今一切都准备好了。编程

2.1 Hello World

我发现正规的编程入门范例老是输出毫无创意的“Hello World”消息。但打破这样的传统彷佛是不敬之举,因此咱们也从这里开始吧,而后再去作一些更有趣的事情。用你喜欢的编辑器建立一个 helloWorld.js 文件:浏览器

var http = require('http'); 
 
http.createServer(function(req,res){ 
    res.writeHead(200, { 'Content-Type': 'text/plain' });  
    res.end('Hello world!'); 
}).listen(3000); 
 
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');

确保是和 helloWorld.js 在同一个目录下,输入 node hello World.js。而后打开浏览器访问http://localhost:3000,你的第一个 Web 服务器就建成啦!这个服务器并无返回 HTML,而只是向你的浏览器传递了一条普通的文本消息“Hello world!” 。若是你想要尝试发送HTML,能够试验一下:只要把 text/plain 换成 text/html,再把 'Hello world!' 换成一个包含有效 HTML 的字符串就好了。在这里就不演示了,由于我要尽可能避免在 JavaScript里写 HTML。服务器

2.2 事件驱动编程

Node 的核心理念是事件驱动编程。这对程序员来讲,意味着你必须知道有哪些事件,以及如何响应这些事件。不少人接触事件驱动编程是从用户界面开始的:用户点击了什么,而后你处理“点击事件” 。这个类比很好,由于程序员不能控制用户什么时间点击或者是
否会点击,因此事件驱动编程真的很直观。在服务器上响应事件这种概念性的跳跃可能会
比较难,但原理是同样的。在前面那个例子中,事件是隐含的:HTTP 请求就是要处理的事件。http.createServer 方
法将函数做为一个参数,每次有 HTTP 请求发送过来就会调用那个函数。咱们这个简单的程序只是把内容类型设为普通文本,并发送字符串“Hello world!” 。

2.3 路由

路由是指向客户端提供它所发出的请求内容的机制。对基于 Web 的客户端 / 服务器端程序而言,客户端在 URL 中指明它想要的内容,具体来讲就是路径和查询字符串(第 6 章会详细讲解 URL 的组成部分) 。
咱们扩展一下“Hello world!”那个例子,作些更有意思的事情。作一个有首页、关于页面和未找到页面的极其简单的网站。目前咱们还像以前那个例子同样,不提供 HTML,只提供普通文本:

var http = require('http'); 
 
http.createServer(function(req,res){ 
    // 规范化 url,去掉查询字符串、可选的反斜杠,并把它变成小写 
    var path = req.url.replace(/\/?(?:\?.*)?$/, '').toLowerCase();  
    switch(path) { 
        case '': 
        res.writeHead(200, { 'Content-Type': 'text/plain' }); 
        res.end('Homepage'); 
        break; 
        case '/about': 
        res.writeHead(200, { 'Content-Type': 'text/plain' }); 
        res.end('About'); 
        break; 
        default: 
        res.writeHead(404, { 'Content-Type': 'text/plain' });  
        res.end('Not Found'); 
        break; 
    } 
}).listen(3000); 
 
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');

运行这段代码,你会发现如今你能够访问首页 (http://localhost: 3000)和关于页面(http://localhost:3000/about) 。全部查询字符串都会被忽略(因此 http://localhost:3000/?foo=bar 也是返回首页) ,而且其余全部 URL(http://localhost:3000/foo)返回的都是未找到页面

2.4 静态资源服务

如今咱们有了一些可用的简单路由,接下来咱们提供一些真正的 HTML 和 logo 图片。由于这些内容不会变化,因此它们都被称为“静态资源” (相对于股票之类的内容,你每次刷新页面,股价都会变化) 。
用 Node 提供静态资源只适用于初期的小型项目,对于比较大的项目,你应该会想用 Nginx 或 CDN 之类的代理服务器来提供静态资源。对此,第 16 章会有更多介绍。
若是你用过 Apache 或 IIS,可能习惯于只是建立一个 HTML 文件,访问它,而后让它自动发送到客户端。Node 不是那样的:咱们必须打开文件,读取其中的内容,而后将这些内容发送给浏览器。因此咱们要在项目里建立一个名为 public 的目录(在下一章中,你就会明白咱们为何无论它叫 static) 。在这个目录下建立文件 home.html、about.html、notfound.html,子目录 img,以及一个名为 img/logo.jpg 的图片。以上这些工做就由你本身来完成了:既然你在阅读这本书,那么你应该知道怎么编写 HTML 文件和找张图片。在你的 HTML 文件中这样引用 logo:

<img href="/img/logo.jpg" alt="logo">

接下来修改 helloWorld.js:

var http = require('http'), 
        fs = require('fs'); 
 
function serveStaticFile(res, path, contentType, responseCode) { 
        if(!responseCode) responseCode = 200;  
        fs.readFile(__dirname + path, function(err,data) { 
                if(err) { 
                        res.writeHead(500, { 'Content-Type': 'text/plain' }); 
                        res.end('500 - Internal Error'); 
                } else {  
                        res.writeHead(responseCode, 
                                { 'Content-Type': contentType }); 
                        res.end(data); 
                }  
        }); 
}
http.createServer(function(req,res){ 
        // 规范化 url,去掉查询字符串、可选的反斜杠,并把它变成小写 
        var path = req.url.replace(/\/?(?:\?.*)?$/, '') 
                .toLowerCase();  
        switch(path) { 
                case '': 
                        serveStaticFile(res, '/public/home.html', 'text/html');  
                        break; 
                case '/about': 
                        serveStaticFile(res, '/public/about.html', 'text/html'); 
                        break; 
                case '/img/logo.jpg': 
                        serveStaticFile(res, '/public/img/logo.jpg', 
                                'image/jpeg');  
                        break; 
                default: 
                        serveStaticFile(res, '/public/404.html', 'text/html', 
                                404);  
                        break; 
        } 
}).listen(3000); 
console.log('Server started on localhost:3000; press Ctrl-C to terminate....');

这 个 例 子 中, 我 们 的 路 由 是 非 常 缺 乏 想 象 力 的。 如 果 你 访 问 http://localhost:3000/about,就返回 public/about.html 文件。你能够随意修改路由,也能够随意修改文件。好比说,若是你一周里的每一天都要换一个关于页
面,你可能会有 public/about_mon.html、public/about_tue.html 等之类的页面,在你的路由中定义好逻辑,从而在用户访问 http://localhost:3000/about 时能提供恰当的页面。注意,咱们建立了一个辅助函数 serveStaticFile,它完成了大部分工做。fs.readFile 是读取文件的异步方法。这个函数有同步版本,fs.readFileSync,但这种异步思考问题的方式,你接触得越早越好。这个函数不复杂:它调用 fs.readFile 读取指定文件中的内容。fs.readFile 读取完文件后执行回调函数,若是文件不存在,或者读取文件时遇到许可权限方面的问题,会设定 err 变量,而且会返回一个 HTTP 500 的状态码代表服务器错误。若是文件读取成功,文件会带着特定的响应码和内容类型发给客户端。 *__dirname 会被解析为正在执行的脚本所在的目录。因此若是你的脚本放在/home/sites/app.js 中,则 __dirname 会被解析为 /home/sites。无论何时,这个全局变量用起来都很方便。若是不这么作,在不一样的目录中运行你的程序时极可能会出现难以诊断的错误。*

相关文章
相关标签/搜索