npm 提供了大量的第三方模块,其中不乏许多Web 框架,而express正是目前最稳定、最流行,且Node.js官方推荐的Web开发框架(Fast, unopinionated, minimalist web framework for Node.js)
express对于Node.js来说(几乎)相当于jQuery对于JavaScript,但express并不是一个无所不包的全能框架,它足够轻量级,多数功能只是对http模块中常用操作的封装,更多的功能需要插件或者整合其他模块来完成
express除了为http模块提供了更高层次的接口外,还实现了以下功能
路由控制
模板解析支持
动态视图
用户会话
CSRF保护
静态文件服务
错误控制器
访问日志
缓存
插件支持
创建项目目录(直接创建或者使用 mkdir 目录名 命令创建)
在该目录下使用
npm install express
就可以本地模式安装最新版express(或者创建package.json文件,指定依赖,然后 npm install 安装所有依赖)
注:使用 npm init 可以在当前目录下交互产生一个package.json
注:默认安装的都是最新版,如果需使用特定版本,则应
npm install [email protected] (指定版本)
当我们已经有了一个项目,并且有了package.json文件时,我们可以使用
以下命令安装express
npm install express --save
这样的话,不仅安装了express,还将express依赖加入到了package.json的依赖列表中
然后就可以在项目文件中引用express,创建app.js,内容如下
var express = require('express'); //引用模块
var app = express(); //创建实例
app.get('/' , function(req , res){
res.send('hello express');
});
app.listen(3000);
运行app.js,就可以访问127.0.0.1:3000了
最后,卸载express模块,则使用
npm uninstall express
除了像上面这样手动创建项目之外,express还允许我们快速快速创建一个项目(Quick Start),迅速建立一个网站最小的基础框架,在此基础上完成开发
注:快速开始工具有些限制,例如默认只能支持部分模板引擎,要知道express本身是支持Node的所有模板引擎的
这时候,需要使用到express命令,还记得,如果一个包是某个项目依赖,那么我们需要在项目的目录下使用本地模式安装这个包,如果要通过命令行调用,则需要用全局模式安装
npm install -g express (4.0.0版本之前)
在4.0.0以后,直接运行该命令尽管成功安装了全局express,却仍不能使用 express 命令新建项目,而要使用
npm install -g express-generator (4.0.0版本之后)
注:算是消除了歧义,我们安装的是express生成器,而不是express模块
默认安装的都是最新版,如果需使用特定版本,则应
npm install -g [email protected] (指定版本)
可以使用
express --version 查看全局express的版本
express –V 一定要大写,否则某些版本不识别
卸载则使用
npm uninstall -g express-generator
全局安装完成后,就可以通过 express 命令快速创建一个项目了
在此之前先查看帮助
express --help 或 express -h
可以看到,最简单的初始化一个项目
express (前提是已经在指定路径下了)
express 项目路径/项目名
express 在初始化一个项目的时候会指定模板引擎,默认为Jade(Jade功能强大但不易学习),在这里暂时使用易于学习的ejs引擎
express –e 项目路径/项目名
然后,控制台会提示我们进入该项目并安装依赖(容易忽略)
然后,控制台会提示我们进入该项目并安装依赖(真的容易忽略)
最基本的框架搭建完成,运行 node ./bin/www ,浏览器输入127.0.0.1:3000,即可看到效果
全局安装的express仅仅让我们使用Quick Start而已,而非项目依赖,所以最新版的全局express,使用了express-generator代替
项目中依赖的express仍然来自于本地node_modules,也就是我们根据依赖下载或者自行安装的express模块
快速建立项目并安装完依赖后,可以看到以下目录
bin目录:用于存放二进制文件(干啥用)
node_modules目录:用于存放本地模块(package.json中依赖的模块)
public目录:用于存放image、css、js等资源文件
routes目录:用于存放路由文件
views目录:用于存放视图文件(网页模板)
app.js文件:项目的启动文件(入口文件)
package.json文件: 项目的配置文件(描述项目信息、指定依赖等)
express框架是建立在node.js核心模块http之上的,在此之前,使用http模块生成服务器的原始代码如下
var http = require('http');
var app=http.createServer(function(req,res){
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('hello\n');
});
app.listen(3000);
使用express框架,则如下
var express = require("express");
var http = require("http");
var app = express();
app.use(function(req, res) {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello world!\n");
});
http.createServer(app).listen(3000);
可见,createServer()方法的参数,从一个回调函数变成了express对象的实例,而实例使用了use()方法,加载了相同的回调函数
所以express框架相当于在http模块上加了一个中间件,而use()方法则调用中间件
中间件就是函数,用来完成各种特定的任务(比如检查用户是否登录、分析数据、以及其他在需要最终将数据发送给用户之前完成的任务)它最大的特点就是,一个中间件处理完,再传递给下一个中间件
createServer方法,可以生成一个服务器实例,该实例允许在运行过程中,调用一系列函数(也就是中间件)。当一个HTTP请求进入服务器,服务器实例会调用第一个中间件,完成后根据设置,决定是否再调用下一个中间件。中间件内部可以使用服务器实例的req和res参数(分别对应ServerRequest和ServerResponse),以及一个next回调函数(即第三个参数)。每个中间件都可以对HTTP请求(request事件)做出回应,并且决定是否调用next方法,将request事件再传给下一个中间件
一个不进行任何操作,只传递request事件的中间件,是这样的
function uselessMiddleware(req, res, next) {
next();
}
注:next()函数若有参数,则代表抛出一个错误,参数即为错误文本,抛出错误后,后面的中间件将不再执行,直到发现一个错误处理函数
注:你访问任何被这两条同样的规则匹配到的路径时,会发现请求总是被前一条路由规则捕获,后面的规则会被忽略。原因是express 在处理路由规则时,会优先匹配先定义的路由规则,因此后面相同的规则被屏蔽
回调函数的第三个参数next(原生的http模块没有这个参数)是控制权转移函数,通过调用next(),会将路由控制权转移给后面的规则
要想使用express,第一步就是require了(废话!)
var express = require('express');
然后,就是创建express实例了
var app =express();
在使用express之前,我们可以对express进行一系列配置,使用set()方法
app.set(name,value);
其中支持以下一些设置项
env 运行环境,默认为process.env.NODE_ENV或者development
trust proxy 支持反向代理,默认禁用
jsonp callback name 改变默认的回调名 ?callback=
json replacer 默认为null
case sensitive routing 路由大小写敏感,默认关闭(不敏感)
strict routing 路由的严格模式,默认 /f和 /f/ 是一样的
view cache 模板缓存,在生产环境中是默认开启的
view engine 设置默认模板引擎
views 模板路径 ,默认"process.cwd() + '/views'"
get()可以获取使用set()设置的值
app.set('name','strong');
app.get('name'); // 'strong'
将设置项name的值设置为true(相当于app.set(name,true))
将设置项name的值设置为false(相当于app.set(name,false))
检查设置项name是否已经启用(是否设置值,包括true)
检查设置项name是否已经禁用(未设置值或者设置为false)
use()方法调用中间件function
可选参数path表示请求路径,省略则默认为”/”
app.use('/' , function(req, res, next) {
console.log("In comes a " + req.method + " to " + req.url);
next();
});
app.use(function(req, res,next) {
res.writeHead(200, { "Content-Type": "text/plain" });
res.end("Hello world!\n");
}).listen(3000);
先调用第一个中间件,然后通过next方法,调用第二个中间件
由于第二个中间件没有调用next方法,所以request事件就不再向后传递
注:路径path对于中间件来说是不可见的,这意味着在req里找不到path,这样做的目的就是让中间件可以在不需要修改代码的情况下在任意路径下执行
使用use方法,可以根据请求的不同网址,返回不同的网页内容
app.use(function(req, res, next) {
if (req.url == "/") {
} else {
next();
}
});
app.use(function(req, res, next) {
if (req.url == "/about") {
} else {
next();
}
});
app.use(function(request, response) {
});
上面代码通过request.url属性,判断请求的网址,从而返回不同的内容
除此之外express允许将请求的网址作为use()方法的第一个参数,因此可以改写为
app.use("/", function(request, response, next) {
});
app.use("/about", function(request, response, next) {
});
app.use("*" , function(request, response) {
//所有路径
});
针对不同的请求,express提供了use方法的一些别名
all()方法表示所有的请求都必须通过该中间件
get()方法表示仅get请求通过该中间件
post()方法表示仅post请求通过该中间件
put()方法表示仅put请求通过该中间件
delete()方法表示仅delete请求通过该中间件
注:这就是REST风格的请求方式(表征状态转移( Representational State Transfer),是一种基于 HTTP 协议的网络应用的接口风格,充分利用 HTTP 的方法实现统一风格接口的服务,Express 对每种 HTTP 请求方法都设计了不同的路由绑定函数,例如前面例子全部是app.get,表示为该路径绑定了 GET 请求,向这个路径发起其他方式的请求不会被响应
该对象包含了请求相关的一些信息
返回
返回查询字符串组成的对象
返回请求的IP地址
返回请求的地址
返回请求的URL的路径名
返回主机名,不包含端口号
返回请求协议
用于设置响应类型
用于设置响应状态
用于设置响应头(同时设置上面两个,甚至更多)
用于获取响应头
用于设置cookie值
用于对网址进行重定向
response.redirect("/hello/anime");
response.redirect("http://www.example.com");
response.redirect(301, "http://www.example.com");
用于发送响应
用于发送文件
用于渲染网页模板
app.get("/", function(request, response) {
response.render("index", { message: "Hello World" });
});
返回一个 JSON 响应
res.json(null)
res.json({ user: 'tobi' })
res.json(500, { error: 'message' })
路由就是指:为不同的访问路径,指定不同的处理方法
这是一个典型的MVC 架构,浏览器发起请求,由路由控制器接受,根据不同的路径定向到不同的控制器。控制器处理用户的具体请求,可能会访问数据库中的对象,即模型部分。控制器还要访问模板引擎,生成视图的HTML,最后再由控制器返回给浏览器,完成一次请求
注:路由相当于MVC架构里的控制器
指定根路径
app.get('/', function(req, res) {
res.send('Hello World');
});
指定特定路径
app.get('/api', function(req, res) {
res.send({name:"张三",age:40});
});
通常把回调函数封装成一个模块,放在routes目录下
// routes/index.js
exports.index = function (req, res){
res.json(200, {name:"张三",age:40});
}
然后,在app.js中加载这个模块。
// app.js
var api = require('./routes');
app.get('/api', api.index);