在正式学习 Express 内容以前,咱们有必要从大的方面了解一下 Node.js 。html
在很长的一段时间里,JavaScript 一门编写浏览器中运行脚本的语言。不过近些年,随着互联网的发展以及技术进步,JavaScript 迎来了一个集中爆发的时代。一个标准性的事件就是 09 年 Node.js 的横空出世。前端
Node.js 由 Google Chrome 的 V8 引擎发展而来,它可以让 JavaScript 运行在服务端。从而极大的拓展了 JavaScript 的应用场景也让 JavaScript 全栈成为了一个热门话题。开发者没必要再去学习 Ruby、Python、Java 等语言和框架,仅仅依靠 JavaScript 就能完成先后端的大部分开发任务。node
虽然,从某些方面来讲 JavaScript 并不完美甚至还有一些设计缺陷,可是这并不影响 Nodejs 的流行。V8 引擎快速处理能力和异步编程风格,让开发者从多线程中解脱了出来。其中,先后端同一技术栈能够说是它最大的杀手锏。而日益丰富的生态环境也让 JavaScript 受到开发者愈来愈多的关注,使用 Node.js 进行开发也变成了一件很是符合潮流的事情了。python
和浏览器环境中的 JavaScript 同样,Node.js 也只提供了构建应用基本所需的底层接口和特性。而这些底层接口通常都很冗长、难用。因此有人就在 Node.js 的基础上实现了 Express 框架。其基本理念与 jQuery 相似,经过对底层接口进行了封装,在简化代码的同时提供更高级的接口。另外,Express 拓展性也很是强。框架自己与程序的架构和业务无关,而且你还能够经过第三方库进行功能拓展。程序员
Node.js (一般简称为 Node )是一个 JavaScript 代码的运行平台。虽然大多数情形下 JavaScript 都运行在浏览器中,可是并无任何地方规定其只能运行在浏览器中。做为一门编程语言,本质上它与 Ruby、Python、C++、PHP 并无什么区别。就像你可使用 python myfile.py 来运行 Python 脚本,你可使用 node myfile.js 来执行 JavaScript 程序。数据库
可是 Node 到底有啥优势值得咱们在服务端开发是尝试呢?express
首先,Node.js 的 JavaScript 引擎很是快。毕竟,它是基于以速度著称的 Google Chrome V8 引擎,能够每秒执行几千条 JavaScript 指令。npm
其次,Node.js 经过异步编程范式将其高并发的能力发挥的淋漓尽致。编程
用现实生活中的烘焙作类比最恰当不过了。假设如今我须要制做一些松饼,那么首先就须要把面粉弄好。而此时我是没法抽身作其余的事情的。可是,一旦我把松饼送进烤箱,我就能够抽身作其余的事情而没必要干等。后端
在 Node.js 中,客户端可能随时都会给服务端发送请求。有可能在你处理一个请求时,另外一个请求也被客户端送达了。假设,两个请求都须要访问数据库。那么就能够在第一个请求进行数据库操做时,转去处理第二个请求。虽然不能同时对二者作成响应,可是咱们可使用异步方式跳过对耗时操做结果的等待直接处理后续请求。而其余的一些运行环境默认是没有此能力的。例如,Ruby on Rails 同时时间只能处理一个请求。若是想提升程序的并发能力,那么你就须要去购买更多的服务器。
下图能够清晰的看出二者的区别:
与同步方式相比,异步处理的效率明显要更高,虽然异步代码也不是并行处理。
固然,这并非说异步处理机制让 Node.js 是世界上最快的语言之一。Node.js 虽然可以最大化压制单核 CPU 的性能,可是仍是没法与多核处理能力相媲美。其余语言中可让你利用多核能力同时执行多个任务。像以前和烘培同样:你能够购买更多的烤箱来同时烤更多的饼干。Node 正在开始支持这个能力,可是它并不像其余语言中那样重要。
就我我的而言,由于性能而选择 Node.js 并非最重要的依据,虽然,它确实比 Ruby、Python 等脚步语言要快。最大的理由是,它在先后端开发中使用同一种语言。
一般,在编写 Web 应用程序时你都会要使用 JavaScript。可是在 Node.js 出现以前,先后端的开发必须使用不一样的语言进行。为此你须要学习多种的语言和框架。有了 Node.js 以后,你就可使用一门语言在先后端开发中自由切换,这是最吸引人的地方。
Express 是一个基于 Node.js 封装的上层服务框架,它提供了更简洁的 API 更实用的新功能。它经过中间件和路由让程序的组织管理变的更加容易;它提供了丰富的 HTTP 工具;它让动态视图的渲染变的更加容易;它还定义了一组可拓展标准。
经过一个简单的 JavaScript 函数,你就能够利用 Node.js 建立一个 Web 程序。该函数用于监听来自浏览器或者其余设备的发起的网络请求。当接收到一个请求后,函数会分析请求的内容并作成相应的处理。例如,当你请求站点主页时,该函数就会知道知道你的目的并将主页的 HTML 渲染出来。若是是请求某个 API 接口,该函数就会把对应的 JSON 数据返回给客户端。
假设,如今须要服务器返回当前时间和时区信息给用户,那么该程序大体包括以下功能:
若是直接在 Node.js 之上构建该应用而不使用 Express 的话,那么完整流程图大抵以下:
在上述流程中,开发人员只须要关注圆圈部份内容处理。
这个用于处理浏览器请求的 JavaScript 函数叫作请求处理函数(request handler)。它也仅仅是一个处理请求并做出响应的 JavaScript 函数,并没有任何特殊之处。Node.js 的 HTTP 服务会接管其中的网络链接,因此你无需关注和处理复杂的网络协议内容。
从代码角度来讲,该函数包含两个参数:一个是网络请求 request 对象 ,另外一个表示网络响应的 response 对象。在前面时间信息应用中,该请求处理函数会检查请求 URL 。若是请求的是主页,那么就返回成功的响应页面。不然,返回 404 错误。没有 Node.js 应用中都是这么处理的:编写处理函数对请求做出响应,很是的简单。
问题在于,Node.js 的 API 对开发者来讲并非很是友好。例如,若是咱们想发送一个 JPEG 图片的话,可能须要至少 45 行代码才行。建立可复用 HTML 模版则更复杂。另外,Node.js 的 HTTP 模块虽然强大,可是仍然缺乏一些实用特性。
Express 的出现就是为了解决这些问题,让你可以高效的使用 Node.js 来编写 Web 应用。
从大的方面来讲,Express 为 Node.js 的 HTTP 模块带来了两大特性:
与上图相比,下图是 Express 处理请求的大体流程:
与以前同样,开发者只须要关注圆圈部分的内容。
虽然,图看起来比前面复杂,可是实际开发却更简单,本质上它主要作了两件事:
利用 Express 提供的简洁 API 接口,经过编写小型 request 请求处理函数,能够极大的压缩代码量提升开发效率。
虽然 Express 是一个框架,可是它的编程规范很是灵活。你能够用它编写各类类型的应用,从视频聊天到我的博客等等。另外,Express 自己并非百宝箱,你可能会在实际开发中须要使用大量第三方类库。这些类库能帮你解决一些次要问题,这样你能够将关注点地放在那些重要的问题上,而后发扬 Unix do-one-thing-well 的哲学将事情处理好。
可是这种最小化理念也是一把双刃剑。一方面,Express 很是灵活可靠,并且不会引入那些无用的垃圾代码。另外一方面,与其余框架相比这种简洁不可避免致使了部分功能缺失。这意味须要在程序架构上作更多的功课,而且在出现问题后要花时间去寻找第三方模块。离开箱即用还差一点。
有人喜欢灵活多变的框架,而有人则喜欢那些结构固定的框架。例如,PayPal 虽然也使用 Express,可是却制定了严格的规范来约束其开发者。Express 自己并不关注程序架构,因此程序员能够根据偏好自行选择。因为对程序有着绝对控制权,因此一旦你作出不明智的决策,那么后面的坑你就慢慢爬吧。
对于大型框架和极简框架的优劣,历来都没有固定的正确答案,因此咱们无须太过纠结。这里,我只但愿你记住 Express 是一个极简框架。
Express 很是简洁并且对 Node.js 的封装效果也很是棒,而这一切都源于框架中的四个设计。
正如以前提到的,原生的 Node.js 使用一个 request 处理函数应对全部请求并作出响应。
Middleware 这个名字起的并很差,可是这个术语并非 Express 独有,相反它已经存在好久了。概念很是简单:咱们不采用一个巨大的 request 请求处理函数,相反咱们将一系列简单的处理函数组合起来。每个小的处理函数对应一个小任务,而这些处理函数就被称为中间件。
中间件能够处理各类任务,从记录请求到发送静态文件到设置 HTTP 头部。例如,应用中使用的第一个中间件功能可能就是记录服务器中每一个请求的 logger-log。当日志记录完成后,它将继续执行调用链中的下一个中间件。而下一个中间件功能可能会去验证用户。若是权限不够,就会使用“未受权”进行提示。反之则继续执行下一个中间件。此时中间件功能可能会是渲染主页并结束响应。下图演示了这两种情形:
在图中能够看出,记录日志的中间件位于第一个而且确定会被执行。紧接着就是执行权限认证的中间件。若是用户权限知足的话就继续执行下一个中间件,不然就再也不执行后续中间件。
中间件最大的特色就是其相对来讲比较标准,这也意味着开发者能够经过为 Express 开发中间件来拓展其功能。同时,这也许意味着某些通用的中间件,颇有可能已经有人开发过来,例如: LESS 和 SCSS 等静态文件的编译、权限控制、cookies 和 sessions 的解析。
相比中间件,Routing 显然更好。与中间价相似,路由对请求处理函数进行了拆分。不一样的是,路由根据请求的 URL 和 HTTP 方法来决定处理方式的。
例如,你的程序中有一个主页和一个留言板页面。当用户使用 GET 去请求主页时,Express 会返回对应的主页内容。对留言板的请求的处理也是如此。若是用户经过 POST 方法在留言板页面中进行了留言操做的话,路由须要作出对应处理并刷新页面。
相似于中间件,上述路由的处理也是经过处理函数进行定义的。而不一样的行为会调用不一样的处理函数。
Express 中的中间件和路由相辅相成。例如:你能够一边记录请求日志,同时对主页路由作出响应。
Express 应用一般都很小,甚至能够是一个文件。随着应用规模的扩张,可能你会将其进行拆分为多个文件和文件夹。虽然 Express 对应用的规模增加没有明确的指导规则。可是咱们能够经过 sub-applications 这一重要特性来做出应对。 在 Express 术语中这些只应用也被称为路由器。
经过实现正常规模的路由器子应用,能够将一个大型应用进行模块拆分。甚至你能够对某些子应用进行更细致的拆分。例如,在应用中可能存在管理后台、单页应用、API 接口 等等几个子模块。这时,你就能够将这些子模块做为一个子应用来实现。详情以下:
当程序规模变大以后,该特性的优点将会逐步凸显出来。
Express 由中间件和路由构成,在其中你须要编写大量的异步处理函数来实现相关功能。
为了使处理过程更加高效正确,Express 在原生的 Node.js 基础上进行了大量的封装。在压缩代码量提升效率的同时也下降了人为错误的几率。除了发送文件以外,Express 提供的 HTML 渲染功能也让原生 Node.js 可望不可即。另外在请求解析方面,Express 也作了很是多的工做。
跟前面的特性不同的是,在保持功能强大的同时这些易用的函数并不会对应用形成负面影响。
像其余的工具同样,Express 并非遗世独立的。
它存活于 Node.js 的生态中,全部你能找到大量的第三发模块提高你的开发效率,例如数据库链接驱动。由于Express 可拓展性极强,全部整个生态中存在大量为 Express 开发的类库。
Express 既不是第一个 Web 框架,固然更不会是最后一个。
一样,Express 也不是 Node.js 生态中的惟一框架。可能它最大的竞争对手就是 Hapi.js 了。与 Express 相似,它也有路由、中间件这就概念。不过不一样的是它没有基于 Node.js 的 HTTP 模块来处理网络请求,而是有 Walmart 开发的网络模块。该模块被 Mozilla,OpenTable 和 NPM 所接受并在真实程序中检验过。做为 Express 的最大竞争对手,所以我怀疑双方的开发人员可能彼此抱有不小敌意。
在 Node.js 世界中最流行的大型框架非全栈式的 Meteor 莫属。相比自由灵活的 Express ,Metero 有着很是严格的程序结构。不一样于 Express 只关注 HTTP 层的处理,Meteor 做为全栈框架能够同时运行在客户端和服务端。固然,这仅仅只是设计上的选择说不上到底谁更优秀。
跟 Express 基于 Node.js 进行封装相似,也有人对 Express 进行更高级的封装。例如,PayPal 创造的 Kraken 。尽管从技术角度来讲,Kraken 不过只是 Express 的一个中间件而已。可是,它仍是作了很多的事情,例如:中间件的安全绑定。Sails.js 则是另外一个以 Express 为基础的新型框架,它内置了数据库、WebSocket 集成、API 生产等等功能。全部的这些框架,都是 Express 的一种相对固定化的封装实现。
Express 最主要的几个特性之一就是中间件。Connect 是一个仅做用于 Node.js 和中间件的框架。它没有提供路由和易用函数接口。而 Express 曾经在它的中间件层中使用了 Connect。虽然如今被抛弃了,可是 Express 中间件一直都彻底兼容 Connect 中间件。这意味着 Express 的火力获得了更大的提高。
除了上面提到的这些,还有不少使用其它语言实现的 Web 框架。
Express 的不少灵感都来自于 Ruby 世界中的轻型 Web 框架 Sinatra。与 Express 相似,Sinatra 中也有路由和中间件功能。Sinatra 框架思想被其余不少语言所借鉴而且从新实现,若是你曾经用过这类框架的话,那么对 Express 必定不会陌生。固然,Express 也借鉴了 Python 中的 Bottle 和 Flask 框架。
相应的,Express 与 Django、Ruby on Rails、ASP.NET 等框架差距巨大。这些框架都十分庞大,并且程序结构也相对固定功能更为丰富。并且,Express 与 PHP 也差别明显,虽然都是运行在服务上可是后者与 HTML 紧耦合。
Express 仅仅是服务端 Web 框架中的一种,因此咱们不能在这里说 Express 就必定比其余的框架好。它具有一些独有的特性,例如,Node.js 的性能以及先后端统一的语言。可是与之同时,它的功能远比其余框架来的少而去 JavaScript 也并非一门获得广大开发者承认的“好”语言。脱离具体场景讨论优劣势没有意义的,下面咱们就看看 Express 一些适用场景。
理论上来讲,Express 能够用来构建任何 Web 应用。对全部请求做出响应这件事上述提到的框架一样可以作到。因此,为何要选择 Express 呢?
最大的优势就是 Node.js 中编写的 JavaScript 能够在浏览器和客户端实现共享。从代码复用角度来讲,这种状况是最理想的。从心理角度来讲也很是有用,开发过程当中无需进行服务器模式和客户端模式的切换。前端开发者能够在不学习新语言的状况下直接就能够编写后端代码。固然,前端开发者仍是须要学习一些新内容的,否则这本书就没存在的必要了。
Express 能够帮助你作到这一点,人们已经为这个技术栈拟好了名称:MEAN 。像 “LAMP” 表明 Linux、Apache、MySQL 和 PHP 同样,“MEAN” 表示 MongoDB、Express、Angular 和 Node.js。人们之因此对它喜好有加是由于它是纯 JavaScript 技术栈。
Express 经常使用于驱动单页应用程序(SPA)。SPA 在前端重度依赖 JavaScript,并且一般须要一个服务器组件。大多数服务器只须要简单的提供 HTML、CSS 和 JavaScript ,可是有时候 REST API 也是常规需求。Express 能够同时完成这两件任务,既能够提供 HTML 也很是适合构建 API 。 Express 相对较低的学习曲线使得前端开发者在几乎无需学习新内容的状况下搭建一个 SPA 服务。
当你使用 Express 编写应用的时候就决定了你必须使用 MEAN 技术栈中的 E 和 N 部分,而对于另外两个 Express 没有作出过限定你彻底能够采用不一样的方案。例如,可使用 Backbone.js 替换其中的 Angular,构成 MEBN 技术栈。使用 SQL 替换 MongoDB 构成 SEAN 技术栈。虽然 MEAN 术语很常见并且配置也很是流行,可是你彻底能够更具须要自行选择。在这本书中咱们将涵盖的技术栈是 MEN:MongoDB、Express 和 Node.js。
另外 Express 还具备一些实时特性。虽然其余语言也支持 WebSocket 和 WebRTC,可是 Node.js 彷佛要更强。这意味着你能够将这些特性应用到 Express 程序中。由于 Node.js 能作的,Express 同样很多。
社区中存在大量能够在 Express 中使用的模块。有一些是 Express 独占的,这些模块与路由和中间件的特性高度兼容。其余的非独占模块也能提高 Express 应用的开发体验和程序性能。
若是你曾经有过 ERB、Jinja二、HAML 等模版引擎的使用经验的话,你就会发现 Express 自带的功能在渲染 HTML 方面简直就是弱鸡。好在 Express 还可使用 EJS 和 Jade 这些社区模版引擎来解决这个问题。
另外,Express 自己并无对数据库作支持。你能够经过文件、关系数据库、或者其余机制来实现数据保存。不事后面将会介绍在 Express 中如何经过 Mongoose 来调用 MongoDB 数据库。
须要注意的一点是:并不存在 Express 模块这一律念,因此第三方库都是 Node.js 模块。Node.js 模块与 Express 相互兼容而且可以配合其工做。全部这些某块都是在 npm 仓库注册的 JavaScript 代码块,而且可使用一致的方法进行安装。与其余环境中同样,模块之间能够相互依赖,而且不一样模块能够相互配合。另外,Express 也不过是 Node.js 中的一个模块而已。
每次学习新内容的时候,绝大多数都是从 Hello World 开始。
那么如今咱们来看看如何使用 Express 构建一个简单的 Hello World 工程。不要太关注代码的细节,后面将会进行详细介绍。代码以下:
var express = require("express"); #A
var app = express(); #B
app.get("/", function(request, response) { #C
response.send("Hello world!"); #C
}); #C
app.listen(3000, function() { #D
console.log("Express app started on port 3000."); #D
}); #D复制代码
A:导入 express 模块并新建变量。
B:建立 app 应用
C:设置访问 Root 路由,并将响应设置为 “Hello world!”。
D:设置程序监听的端口,并打赢服务启动成功的信息。
再次提醒一下,没有所有弄懂代码没关系,后面会有更详细的讲解。
你立刻就能学到关于 Express 的全部知识了。
本文主要介绍了:
原文地址