安装 express
在目标文件夹下执行如下命令:
cnpm i express
安装完后,在目标文件夹下新建index.js文件:
// 引入 express 模块
var express = require('express');
// 创建 express 实例
var app = express();
// 响应HTTP的GET方法
app.get('/', function (req, res) {
res.send('Hello World!');
});
// 监听到8000端口
app.listen(8000, function () {
console.log('Hello World is listening at port 8000');
});
然后在Node.js的命令行环境下执行“node index.js”命令,网站就运行起来了。浏览器访问一下,可以输出相应的信息。
使用
const express = require("express");
const app = express();
// 处理文件路径的模块
const path = require("path");
// view处理
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");
// 定义一个存放静态资源的目录
app.use(express.static("src"));
// 页面路由的处理,此处表示首页的时候处理index
const index = require("./routes/index");
app.use("/", index);
const server = app.listen(8080, function(){
console.log("启动成功!");
})
中间件
官方介绍:
http://expressjs.com/zh-cn/guide/writing-middleware.html
http://expressjs.com/zh-cn/guide/using-middleware.html
Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。
中间件(Middleware) 就是处理HTTP请求的函数,它最大的特点就是,一个中间件处理完,再传递给下一个中间件。App实例在运行过程中,会调用一系列的中间件。
每个中间件可以从App实例,接收三个参数,依次为request对象(代表HTTP请求)、response对象(代表HTTP回应),next回调函数(代表下一个中间件)。每个中间件都可以对HTTP请求(request对象)进行加工,并且决定是否调用next方法,将request对象再传给下一个中间件。
use方法
use是express注册中间件的方法,它返回一个函数。下面是一个连续调用两个中间件的例子。
var express = require("express");
var http = require("http");
var app = express();
app.use(function(request, response, next) {
console.log("In comes a " + request.method + " to " + request.url);
next();
});
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello world!\n");
});
http.createServer(app).listen(1337);
上面代码使用app.use方法,注册了两个中间件。收到HTTP请求后,先调用第一个中间件,在控制台输出一行信息,然后通过next方法,将执行权传给第二个中间件,输出HTTP回应。由于第二个中间件没有调用next方法,所以request对象就不再向后传递了。
use方法内部可以对访问路径进行判断,据此就能实现简单的路由,根据不同的请求网址,返回不同的网页内容。
var express = require("express");
var http = require("http");
var app = express();
app.use(function(request, response, next) {
if (request.url == "/") {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the homepage!\n");
} else {
next();
}
});
app.use(function(request, response, next) {
if (request.url == "/about") {
response.writeHead(200, { "Content-Type": "text/plain" });
} else {
next();
}
});
app.use(function(request, response) {
response.writeHead(404, { "Content-Type": "text/plain" });
response.end("404 error!\n");
});
http.createServer(app).listen(1337);
上面代码通过request.url属性,判断请求的网址,从而返回不同的内容。注意,app.use方法一共登记了三个中间件,只要请求路径匹配,就不会将执行权交给下一个中间件。因此,最后一个中间件会返回404错误,即前面的中间件都没匹配请求路径,找不到所要请求的资源。
除了在回调函数内部判断请求的网址,use方法也允许将请求网址写在第一个参数。这代表,只有请求路径匹配这个参数,后面的中间件才会生效。无疑,这样写更加清晰和方便。
app.use('/path', someMiddleware);
上面代码表示,只对根目录的请求,调用某个中间件。
因此,上面的代码可以写成下面的样子。
var express = require("express");
var http = require("http");
var app = express();
app.use("/home", function(request, response, next) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the homepage!\n");
});
app.use("/about", function(request, response, next) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the about page!\n");
});
app.use(function(request, response) {
response.writeHead(404, { "Content-Type": "text/plain" });
response.end("404 error!\n");
});
http.createServer(app).listen(1337);
当你不写路径的时候,实际上就相当于"/",就是所有网址
路由get、post这些东西,也是中间件,中间件讲究顺序,匹配上第一个之后,就不会往后匹配了,next函数才能够继续往后匹配。如下实例:
app.get("/",function(req,res,next){
console.log("1");
next();
});
app.get("/",function(req,res){
console.log("2");
});
all方法和HTTP动词方法
针对不同的请求,Express提供了use方法的一些别名。比如,上面代码也可以用别名的形式来写。
var express = require("express");
var http = require("http");
var app = express();
app.all("*", function(request, response, next) {
response.writeHead(200, { "Content-Type": "text/plain" });
next();
});
app.get("/", function(request, response) {
response.end("Welcome to the homepage!");
});
app.get("/about", function(request, response) {
response.end("Welcome to the about page!");
});
app.get("*", function(request, response) {
response.end("404!");
});
http.createServer(app).listen(1337);
上面代码的all方法表示,所有请求都必须通过该中间件,参数中的“*”表示对所有路径有效。get方法则是只有GET动词的HTTP请求通过该中间件,它的第一个参数是请求的路径。由于get方法的回调函数没有调用next方法,所以只要有一个中间件被调用了,后面的中间件就不会再被调用了。
除了get方法以外,Express还提供post、put、delete方法,即HTTP动词都是Express的方法。
这些方法的第一个参数,都是请求的路径。除了绝对匹配以外,Express允许模式匹配。
app.get("/hello/:who", function(req, res) {
res.end("Hello, " + req.params.who + ".");
});
上面代码将匹配“/hello/alice”网址,网址中的alice将被捕获,作为req.params.who属性的值。需要注意的是,捕获后需要对网址进行检查,过滤不安全字符,上面的写法只是为了演示,生产中不应这样直接使用用户提供的值。
如果在模式参数后面加上问号,表示该参数可选。
app.get('/hello/:who?',function(req,res) {
if(req.params.id) {
res.end("Hello, " + req.params.who + ".");
}
else {
res.send("Hello, Guest.");
}
});
set方法
set方法用于指定变量的值。
app.set("views", __dirname + "/views");
app.set("view engine", "jade");
上面代码使用set方法,为系统变量“views”和“view engine”指定值。
response对象
API | 含义 |
---|---|
res.app | 同req.app |
res.append() | 追加指定HTTP头 |
res.set() | 在res.append()后将重置之前设置的头 |
res.cookie() | 设置Cookie |
res.clearCookie() | 清除Cookie |
res.download() | 传送指定路径的文件 |
res.get() | 返回指定的HTTP头 |
res.json() | 传送JSON响应 |
res.jsonp() | 传送JSONP响应 |
res.location() | 只设置响应的Location HTTP头,不设置状态码或者close response |
res.redirect() | 设置响应的Location HTTP头,并且设置状态码302 |
res.send() | 传送HTTP响应 |
res.sendFile() | 传送指定路径的文件 -会自动根据文件extension设定Content-Type |
res.set() | 设置HTTP头,传入object可以一次设置多个头 |
res.status() | 设置HTTP状态码 |
res.type() | 设置Content-Type的MIME类型 |
(1)response.redirect方法
response.redirect方法允许网址的重定向。
response.redirect("/hello/anime");
response.redirect("http://www.example.com");
response.redirect(301, "http://www.example.com");
res.redirect()默认响应状态码是302
可以更改这个状态码作为res.redirect()的第一个参数
//app.js
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.redirect(302, 'demo');
});
app.get('/demo', function(req, res){
res.end();
});
app.listen(3000);
当在url地址栏中输入http://localhost:3000
页面就会重定向到http://localhost:3000/demo
(2)response.sendFile方法
response.sendFile方法用于发送文件。
response.sendFile("/path/to/anime.mp4");
(3)response.render方法
response.render方法用于渲染网页模板。
app.get("/", function(request, response) {
response.render("index", { message: "Hello World" });
});
上面代码使用render方法,将message变量传入index模板,渲染成HTML网页。
(4)res.send()
res.send用于向客户端响应信息
并且它的强大之处在于可以智能的处理我们传递的不同类型参数
app.get('/', function(req, res, next){
res.send('express');
});
当参数为字符串,会将响应头Content-Type默认设置为text/html
也就是解析为html呈现在我们的页面上
app.get('/', function(req, res){
res.send(200);
});
当参数为数字,会自动帮我们设置响应体(状态码…)
app.get('/', function(req, res){
res.send([1, 2, 3]);
});
当参数为数组或对象,它会响应一个JSON
requst对象
API | 含义 |
---|---|
req.app | 当callback为外部文件时,用于访问express的实例 |
req.baseUrl | 获取路由当前安装的URL路径 |
req.body/cookies | 获得「请求主体」/ Cookies |
req.fresh/stale | 判断请求是否还「新鲜」 |
req.hostname/ip | 获取主机名和IP地址 |
req.originalUrl | 获取原始请求URL |
req.params | 获取路由的parameters |
req.path | 获取请求路径 |
req.protocol | 获取协议类型 |
req.query | 获取URL的查询参数串 |
req.route | 获取当前匹配的路由 |
req.subdomains | 获取子域名 |
req.acceptsCharsets | 返回指定字符集的第一个可接受字符编码 |
req.acceptsEncodings | 返回指定字符集的第一个可接受字符编码 |
req.acceptsLanguages | 返回指定字符集的第一个可接受字符编码 |
req.accepts() | 检查可接受的请求的文档类型 |
req.get() | 获取指定的HTTP请求头 |
req.is() | 判断请求头Content-Type的MIME类型 |
(1)request.ip
request.ip属性用于获得HTTP请求的IP地址。
(2)request.files
request.files用于获取上传的文件。
(3)req.query
req.query可以获取请求路径参数的对象
向服务器发送请求 http://localhost:3000/?user=tester&pass[a]=123&pass[b]=456
//app.js
var express = require('express');
var app = express();
app.get('/', function(req, res, next){
console.log(req.query);
console.log(req.query.user); //tester
console.log(req.query.pass.a); //123
console.log(req.query.pass.b); //456
res.end();
});
app.listen(3000);
(4)req.params
req.params可以解析复杂路由规则上的属性
(req.param综合了req.query和req.param的功能,但是被移除了不要使用)
向服务器发送请求 http://localhost:3000/123456
//app.js
var express = require('express');
var app = express();
app.get('/:id', function(req, res, next){
console.log(req.params.id); //123456
res.end();
});
app.listen(3000);
这样不论我在根路径后输入的是什么都会被解析为req.params.id
静态资源
静态资源就是指我们在开发中用到的css、js、img等等
它们需要存放到一个静态资源目录
当浏览器发出了一个非HTML文件请求
服务器就会从这个静态资源目录下去查找文件
我们一般在根目录下创建一个public文件来存储
并在public中创建stylesheets、javascripts、images等文件夹
用来存储特定类型的资源
指定静态资源目录的方法上面已经提到了
var path = require('path');
app.use(express.static(path.join(__dirname, 'public')));
比如说我们的html中有这样的代码
<link href="/javascripts/jquery.js" rel="stylesheet" media="screen">
那么客户端运行发出请求
服务器就会在public的javascripts文件夹下找到jquery.js静态资源
模板引擎
express框架默认是ejs和jade渲染模板
路由
路由的意思就是根据不同的路径,来指定不同的处理方法
我们一般把不同的路由封装进不同的模块
首先在根目录下创建一个文件夹routes存储路由
现在我在routes文件夹下创建俩个路由文件index.js和users.js
修改app.js
//app.js
var express = require('express');
var path = require('path');
var app = express();
var index = require('./routes/index');
var users = require('./routes/users');
app.use('/', index);
app.use('/users', users);
app.listen(3000);
这样表示http://localhost:3000/的路由交给index处理
http://localhost:3000/users的路由交给users处理
下面简单的实现一下路由
//routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res){
res.end('index');
});
router.get('/123', function(){
res.end(123);
});
module.exports = router;
//routes/users.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.end('users');
});
module.exports = router;
通过express.Router()创建的router就像一个mini版的app一样
app能做的,router都能做
只是我们把逻辑都封装到了各个路由模块中
上面代码的结果:
body-parser中间件
其实express在3.x版本中内置了很多中间件
但是4.x版本就将出static以外的所有中间件全部抽离出来了
所以就需要我们单独安装
对照表如下:
Express 3.0 | Express 4.0 |
---|---|
bodyParser | body-parser |
compress | compression |
cookieSession | cookie-session |
logger | morgan |
cookieParser | cookie-parser |
session | express-session |
favicon | static-favicon |
response-time | response-time |
error-handler | errorhandler |
method-override | method-override |
timeout | connect-timeout |
vhost | vhost |
csrf | csurf |
刚才就提到了POST请求有所不同
不同的地方就在于我们需要body-parser这个中间件来处理数据
通过req.body来获得数据
首先使用前不要忘记下载
npm install body-parser --save
//app.js
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/', function(req, res){
res.send('<form method="POST" action="./form">\
<input type="text" name="user">\
<input type="submit">\
</form>');
});
app.post('/form', function(req, res){
console.log(req.body);
var user = req.body.user;
res.send('账号: ' + user);
});
app.listen(3000);
下面这四个方法分别用于对body内容采取不同的处理方法
bodyParser.json(options) 处理JSON数据
bodyParser.raw(options) 处理buffer数据
bodyParser.text(options) 处理文本数据
bodyParser.urlencoded(options) 处理UTF-8编码数据
这样我首先通过get请求获取主页面
提交表单向服务器发送post请求
服务器响应结果
express-generator:使用express搭建应用结构
express模块有一个命令行工具express,可以用来生成基于express模块的应用结构(网站结构)。
express 4.x之后,express命令被独立出来放在了express-generator模块中。我们用下面的命令全局安装express这个命令行工具:
cnpm install -g express-generator
安装完成后,在命令行环境下执行“express --version”,可以看到express的版本是4.16.1。
好了,现在我们使用express命令来创建一个默认的网站。
在命令行环境下导航到node.js这个目录下,执行下面的命令:
express FirstExpress
然后可以看到:
仔细看上面的图哦,它告诉了我们三类非常重要的信息:
express命令创建的网站的目录结构以及创建的文件
安装依赖(进入到HelloExpress下,执行npm install)
使用npm start启动网站(express 4.x后)
按照响应的提示依次执行:
cd FirstExpress
cnpm install
npm start
很快就可以看到下面的图:
看到上图,说明网站已正常运行。你可以在浏览器里访问http://localhost:3000,然后就可以看到这个页面:
到这里,express框架就搭建成功!
最后附上API中文地址:https://cloud.tencent.com/developer/section/1489347