Node与express开发

摘要:
简化是Express最吸引人的功能之一。灵活的Express理念的另一个关键点是可扩展性。单页程序可以使用Angular或Ember等流行框架开发,Express可以很好地使用它们。如果您仍然对Express是什么感到困惑,请不要担心。有时只是使用一些东西。本书将教您如何在不首先了解Express的情况下开发Web程序。

1.初识Express

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

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

灵活
Express 哲学中的另一个关键点是可扩展。Express 提供了一个非常精简的框架,你可以根据自己的需要添加 Express 功能中的不同部分,替换掉不能满足需要的部分。这种做法很新鲜。很多框架把什么都给你了,一行代码还没写,你拥有的就已经是一个臃肿、神秘而复杂的项目了。通常,你的第一项任务就是把不需要的功能砍掉,或者替换掉不能满足需求的功能。Express 则采取了截然不同的方式,让你在需要时才去添加东西。

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

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

多页和混合的Web程序
多页 Web 程序是更传统的方式。网站上的每个页面都是通过向服务器发起单独的请求得到的。这种方式确实比较传统,但这并不意味着它没有优点,或者说单页程序更好。只是现在有更多选择了,你可以决定哪些内容应该作为单页程序提供,哪些应该通过不同的请求提供。 “混合”说的就是同时使用这两种方式的网站。
如果你还是很困惑 Express 究竟是什么,不用担心。有时候只管把某些东西拿来用就好了,不用先理解它是什么,本书将教你如何用 Express 开发 Web 程序。

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="http://t.zoukankan.com/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。不管什么时候,这个全局变量用起来都很方便。如果不这么做,在不同的目录中运行你的程序时很可能会出现难以诊断的错误。

免责声明:文章转载自《Node与express开发》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇数据库(DB)dstat命令下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JavaWeb之Cookie和Session的区别

Cookie和Session的区别 一、cookie机制和session机制的区别 ************************************************************************************* 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态...

菜单树jstree.js插件几个主要事件汇总

jstree.js是一个很强大管理菜单的插件,奈何中文的文档或者案例太少了,用起来很痛苦,下面我就介绍这段时间我经常用到,平时项目也经常用到的几个知识点。 参考了一下文章: https://blog.csdn.net/j1137573560/article/details/82821839 https://www.cnblogs.com/chenjunsh...

服务器常用的状态码

常见HTTP状态码 Type Reason-phrase Note 1XX Informational 信息性状态码,表示接受的请求正在处理 2XX Success 成功状态码,表示请求正常处理完毕 3XX Redirection...

Eclipse没有 web Project 选项的解决办法

装下插件即可。步骤如下: 选择 Help >Software Updates >Find and Install。这个选项会让您可以下载和安装 Web 工具,且无需转到 Web 站点。选择 Search for New Features to Install,如下所示,然后单击 Next。选择 Callisto Discovery Site,如...

[Linux实用工具]Linux监控工具munin的安装和配置

〇、摘要 munin是用于Linux系统(也可以监控windows系统)的监控软件。munin除了可以监控系统的各项数值之外,最大的好处是可以自己编写插件自定义监控需要的数值。整个系统的架构简单明了,操作方便。如果是使用Debian或者Ubuntu安装,安装过程也非常简单。munin除了可以监控结果,也可以设置报警。对于我个人对性能测试的工作来说,是个非常...

K8s Master当作Node使用的方法

1、使用下面的命令操作使得master 可以作为node使用 承载pod kubectl taint nodes --all node-role.kubernetes.io/master- 可能会出现下面的结果 因为taint(master标记的污点已经被去掉了)没有关系 taint "node-role.kubernetes.io/master" not...