20190220 学习Express框架

Express简介

是一个简洁而灵活的node.js Web应用框架,提供了一系列强大特性帮助创建各种Web应用和丰富的HTTP工具

核心特性

  1. 可以设置中间件来响应HTTP请求
  2. 定义了路由表用于执行不同的HTTP请求动作
  3. 可以通过向模板传递参数来动态渲染HTML页面

路由

路由的介绍

可以为一个路径同时映射多个路由,这样当访问该路径时,多个路由都会被触发,触发顺序是按照路由的设置顺序触发的,多个路由只能返回一个响应;
同一次请求里的req和res一定是相同的对象,哪怕是配置的多个路由;
可以通过next来控制路由是否向下进行,如果不调用next,则不会向下继续,而调用next则会触发下一个路由

路由的设置

路由的设置方式:

app.<method>(path,callback);

< method>表示要处理的请求方式,可以是get post或all;
path 是服务器端的路径,也是要映射的路径,以斜杠/开头,斜杠/代表根目录;
callback是当路由匹配到时需要执行的函数,当path对应的地址被访问时,要调用的回调函数,回调函数中有三个参数——req、res、next
以下为设置路由的两种方式:

app.get("/hello",function (req , res , next) {});
// GET 方法请求路由
app.get('/', function (req, res) {
  res.send('GET request to the homepage');
});

// POST 方法请求路由
app.post('/', function (req, res) {
  res.send('POST request to the homepage');
});
路由路径

路由路径和请求方法一起定义了请求的端点,可以是字符串、字符串模式、正则表达式

url地址的格式:
协议名://域名/ip地址:端口号/路径/资源名?查询字符串
相对路径:
指相对于当前资源所在目录的位置;
在服务器中,路径都是相对于虚拟路径的;
相对路径使用.或..开头,或者直接写路径;“.”或直接写路径表示在当前文件夹中寻找;”..”表示去上一级文件夹中寻找;
绝对路径:
绝对路径使用“/”开头;
/代表的是服务器中的根目录;
绝对路径永远相对于服务器的根目录,不会因为文件的位置的改变而改变;
在开发环境是服务器的时候,应该使用绝对路径,而不是用相对路径;

request和response对象
request对象

request对象表示HTTP请求,包含了请求查询字符串、参数、内容、HTTP头部等属性
常见属性——
req.hostname / req.ip:获取主机名和IP地址;
req.originalUrl:获取原始请求URL,请求首页的路径;
req.path:获取请求路径
req.protocol:获取协议类型
req.query:获取URL的查询参数串
req.route:获取当前匹配的路由
req.header:所有的请求头
req.get():获取指定的HTTP请求头
req.is():判断请求头Content-Type的MIME类型

response对象

response对象表示HTTP响应,即在接收到请求时服务器向客户端发送的HTTP响应数据
常见属性——
res.set()在res.append()后将重置之前设置的头;
res.set():设置HTTP头,传入object可以一次设置多个头
res.download():
将文件设置为响应头并提供给客户端进行下载;
使用该方法发送的文件,无论浏览器是否能打开,都会弹出下载窗口;
res.sendFile( pa th [,o pt io n s ] [,f n ] ):将文件设置响应体并发送给客户端;使用该方法发送的文件,如果浏览器能打开则自动打开,否则将会弹出下载窗口。
将文件设置响应体并发送给客户端
使用该方法发送的文件,如果浏览器能打开则自动打开,否则将会弹出下载窗口;
res.get():返回指定的HTTP头
res.location():只设置响应的Location HTTP头,不设置状态码或者close response
res.send():传送HTTP响应,设置的仅仅只是响应体!而响应首行和响应响应头默认已经设置好了。注意,send请求只能调用一次!
res.sendStatus()服务器发送给浏览器的响应状态码;

get方式设置路由

app.get()用来设置get()路由
参数为两个,一个为路由映射的请求地址,第二个为回调函数

app.get('/example/b', function (req, res, next) {
  console.log('通过路由发送内容');
  next();
}, function (req, res) {
  res.send('你好,我是hello路由返回的内容');
});

post方式设置路由

app.post()用来设置post路由

app.post('/process_post', urlencodedParser, function (req, res) {
 
   // 输出 JSON 格式
   var response = {
       "first_name":req.body.first_name,
       "last_name":req.body.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})

Express.Router

Express.Router作为一个单独的组件,类似小型的express应用程序一样,有自己的use、get、param、route方法
使用 express.Router 类创建模块化、可挂载的路由句柄,Router 实例是一个完整的中间件和路由系统,因此常称其为一个 “mini-app”

基本用法

Express.Router是一个构造函数,调用后返回一个路由器实例。然后,使用该实例的HTTP动词方法,为不同的访问路径指定回调函数;最后,挂载到某个路径

var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
  res.send('首页');
});
router.get('/about', function(req, res) {
  res.send('关于');
});
app.use('/', router);

router.use()方法为router对象指定中间件,在数据正式发给用户之前,对数据进行处理

router.use(function(req, res, next) {
    console.log(req.method, req.url);
    next();    
});

router.param()方法用于路径参数的处理,param方法必须放在HTTP动词方法之前

router.param('name', function(req, res, next, name) {// 对name进行验证或其他处理……    console.log(name);
    req.name = name;
    next();    
});
router.get('/hello/:name', function(req, res) {
    res.send('hello ' + req.name + '!');
});

HTTP模块

express框架建立在node.js内置的http模块上
http模块生成服务器的原始代码如下:

var http = require("http");
var app = http.createServer(function(request,response){
  response.writeHead(200, {"Content-Type":"text/plain"});
  response.end("Hello world!");
});
app.listen(3000, "localhost");

express框架的核心是对http模块的再包装:

var express = require('express');
var app = express();
app.get('/', function (req, res) {
  res.send('Hello world!');
});
 
app.listen(3000);

两者差别在于express框架在http模块上加了一个中间层

中间件

express和中间件的关系

Express 是一个自身功能极简,完全是由路由和中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件

中间件的性质

每个中间件都是一个handler,用来处理HTTP请求的函数,依次传入request,response,next三个参数
中间件讲究顺序,匹配上第一个之后,就不会往后匹配了。next函数才能够继续往后匹配
基本的中间件结构如下:

function myFunMiddleware(request, response, next) {
    // 对request和response作出相应操作
    // 操作完毕后返回next()即可转入下個中间件
    next();
}

中间件的功能

  1. 执行任何代码
  2. 修改请求和相应对象
  3. 终结请求-响应循环
  4. 调用堆栈中的下一个中间件
    如果当前中间件没有终结请求-响应循环,则必须调用next()方法将控制权交给下一个中间件,否则请求就会被挂起

中间件的分类

Express应用可以使用如下几种中间件:

  1. 应用级中间件
    应用级中间件绑定到app对象,使用app.use(),app.get(),app.post(),app.put()
  2. 路由级中间件
    路由级中间件绑定的对象为express.Router()
  3. 错误处理中间件
    错误处理中间件和其他中间件定义类似,只是要使用4个参数:err,req,res,next
app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});
  1. 内置中间件
    express.static是express唯一内置的中间件,基于serve-static,负责在express应用中托管静态资源
  2. 第三方中间件
    通过使用第三方中间件从而为express应用增加更多功能。
    安装所需功能的node模块,并在应用中加载,可以在应用级加载,也可以在路由级加载

use方法

use是express注册中间件的方法,它返回一个函数
调用几次app.use()就注册了几个中间件
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);

方法二:
允许将请求网址写在第一个参数,表示只有请求路径匹配了这个参数,后面的中间件才生效

app.use('/path', someMiddleware);

API

express()

创建Express应用程序
express()函数是express模块导出的顶级函数

var express = require('express');
var app = express();
express.json([options])

是Express中的内置中间件功能,使用JSON有效负载解析传入的请求

express.static(root,[options])

是Express中的内置中间件功能
提供静态文件,基于serve-static,root参数指定从中提供静态资源的根目录
该函数通过req.url与提供的root目录组合来确定要提供的文件,当找不到文件时,它不是返回404响应,而是调用next()继续下一个中间件,允许堆叠和回退

exoress.Router([options])

创建一个新的路由器对象

var router = express.Router([options]);

可选options参数指定路由器的行为:

  1. caseSensitive
    启用区分大小写,默认情况下禁用
  2. mergeParams
    保留req.params父路由器的值。如果父级和子级具有冲突的参数名称,则子级的值优先。默认值为false
  3. strict
    启用严格路由,默认情况下禁用
express.urlencoded([options])

是Express中的内置中间件功能
可选options对象的属性值如下:

  1. extended
  2. inflate
  3. limit
  4. parameterLimit
  5. type
  6. verify
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容