菜单

技术栈开发web应用

2019年11月3日 - 银河官方网站
技术栈开发web应用

用“MEAN”工夫栈开荒web应用(二卡塔 尔(英语:State of Qatar)express搭建服务端框架

2015/11/14 · 底工才干 ·
MEAN

初稿出处:
吕大豹   

上一篇咱俩讲了何等运用angular搭建起项指标前端框架,前端抽象出一个service层来向后端发送乞请,后端则赶回相应的json数据。本篇大家来介绍一下,怎样在nodejs情形下行使express来搭建起服务端,使之不易的响应前端的央浼。本文所讲的亲自去做照旧依据大家的就学项目QuestionMaker()

个人才具学习笔记,如有肖似,纯属平常,请勿喷,谢谢同盟。

express 项目 最棒永不全局安装 直接在当前目录下 npm install express
–save
生成器 cnpm install express-generator -g
然后express -h 查看是还是不是成功
运用express myapp 成立 cnpm install 安装信任项 set DEBUG=myaoo & npm
start 运维

路由(Routing卡塔尔国是由三个 U兰德酷路泽I(也许叫路径卡塔 尔(英语:State of Qatar)和叁个特定的 HTTP
方法(GET、POST
等卡塔 尔(阿拉伯语:قطر‎组成的,涉及到应用怎么着响应顾客端对有些网址节点的探望。
每贰个路由都得以有三个依旧多少个Computer函数,当相称到路由时,那个/些函数将被实行。
路由的定义由如下结构组成:
app.METHOD(PATH, HANDLER)

// 网址首页选取 POST 伏乞
app.post(‘/’, function (req, res) {
res.send(‘Got a POST request’);
});

Express 内置的 express.static
能够方便地托管静态文件,举例图片、CSS、JavaScript 文件等。
将静态能源文件所在的目录作为参数字传送递给 express.static
中间件就足以提供静态能源文件的拜见了。举例,借使在 public
目录放置了图片、CSS 和 JavaScript
文件,你就能够:app.use(express.static(‘public’));
假使您的静态能源寄存在三个目录上边,你可以一再调用 express.static
中间件:
app.use(express.static(‘public’));
app.use(express.static(‘files’));

app.all() 是三个优越的路由方法,未有任何 HTTP
方法与其对应,它的法力是对于二个门道上的具有诉求加载中间件。
app.all(‘/secret’, function (req, res, next) {
console.log(‘Accessing the secret section …’);
next(); // pass control to the next handler
});

路由路线和倡议方法一齐定义了央求的端点,它可以是字符串、字符串方式可能正则表明式。
字符串:
// 相称 /about 路线的央求
app.get(‘/about’, function (req, res) {
res.send(‘about’);
});

// 相配 /random.text 路线的乞请
app.get(‘/random.text’, function (req, res) {
res.send(‘random.text’);
});
字符串形式:
// 匹配 abcd、abxcd、abRABDOMcd、ab123cd等
app.get(‘/abcd’, function(req, res) {
res.send(‘ab
cd’);
});
// 匹配 /abe 和 /abcde
app.get(‘/ab(cd)?e’, function(req, res) {
res.send(‘ab(cd)?e’);
});
正则:
// 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等
app.get(/.fly$/, function(req, res) {
res.send(‘/.
fly$/’);
});

运作起基于express的web服务器

express是一个web应用开采框架,它依照nodejs,扩张了累累web开垦所需的职能,使得我们能够很有利的拜见和操作request和response。请当心它和nginx可能tomcat并非三个概念,它是三个开销框架,并非服务器。

运营起基于express的web服务器是特别轻易的,因为express都绑你封装好了。首先须求用npm安装好express,然后在品种根目录下新建七个server.js文件,内容如下:

JavaScript

var express = require(‘express’); var app = express(); app.listen(3000);
var _rootDir = __dirname; var protectDir = _rootDir + ‘/protect/’;
app.use(express.static(_rootDir)); //注册路由 app.get(‘/’,
function(req, res){ res.sendFile(_rootDir+’/src/index.html’); });
app.use(function(req, res, next) {
res.status(404).sendFile(_rootDir+’/src/404.html’); });
app.use(function(err, req, res, next) { console.error(err.stack);
res.status(500).send(‘500 Error’); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var express = require(‘express’);
var app = express();
app.listen(3000);
 
var _rootDir = __dirname;
var protectDir = _rootDir + ‘/protect/’;
 
app.use(express.static(_rootDir));
 
//注册路由
app.get(‘/’, function(req, res){
    res.sendFile(_rootDir+’/src/index.html’);
});
 
app.use(function(req, res, next) {
     res.status(404).sendFile(_rootDir+’/src/404.html’);
});
app.use(function(err, req, res, next) {
     console.error(err.stack);
     res.status(500).send(‘500 Error’);
});

上述代码完成了那多少个效果与利益,首先创立了http服务器,监听在3000端口。

然后app.use(express.static(_rootDir));那大器晚成行是应用了静态文件服务的中间件,那样大家项目下的js、css甚至图片等静态文件就都足以访谈到了。

接下去是注册路由,此处只卓殊五个路由准绳,那就是”/”(网站的根目录卡塔尔,当匹配到此路由后把首页文件index.html直接用res.sendFile方法给发送到浏览器端。那样浏览器用

可是在本项目中,我们用的是angular的前端模板,所现在端就无需模板了,未有开展安顿。咱们的路由机制也是一心使用的ng的前端路由,所以在express中只布置一条就够了。

在最后还会有两块代码,分别是404和500荒诞的破获。你也许会纳闷为何是如此写吗?从上到下排下来就能够分别捕获404和500了吗?其实这正是express的中间件机制,在这里编制下,对客商端哀告的管理疑似多少个流水生产线,把装有中间件串联起来,只要某当中间件把央求再次来到了,就终止施行,不然就从上到下一向管理此呼吁。

地方代码的流水生产线正是,先按路由法则来同盟路线,若是路由特不到,则认为是发出404。500的荒诞请留意叁个细节,在回调函数的参数中,第多个会传播err,正是不对对象,以此来标志是叁个500荒唐。

路由句柄

可感到呼吁管理提供三个回调函数,其一颦一笑看似中间件。唯风流洒脱的分别是这么些回调函数有希望调用
next(‘route’)
方法而略过任何路由回调函数。能够应用该机制为路由定义前提条件,假诺在现成路径上继续实行未有意义,则可将调控权交给剩下的路子。
路由句柄有两种格局,能够是一个函数、三个函数数组,只怕是多头交织,如下:
var cb0 = function (req, res, next) {
console.log(‘CB0’);
next();
}

var cb1 = function (req, res, next) {
console.log(‘CB1’);
next();
}

app.get(‘/example/d’, [cb0, cb1], function (req, res, next) {
console.log(‘response will be sent by the next function …’);
next();
}, function (req, res) {
res.send(‘Hello from D!’);
});

明白中间件

express的着力是中间件机制,通过应用各样中间件,能够贯彻灵活的组装大家所需的效果与利益。中间件是在管道中执行的,所谓管道便是像流水生产线相仿,每达到一个加工区,相应的中间件就足以管理request和response对象,管理完后再送往下叁个加工区。若是有些加工区把须求终结了,比方调用send方法重回给了客户端,那么管理就告意气风发段落了。大部分地方下,皆有现存的中间件供大家运用,举例用body-parser分析央浼实体,用路由(路由也是风度翩翩种中间件卡塔尔国来不易的派发须求。

比方说大家在server.js中增加如下的代码:

JavaScript

app.use(function(req, res, next){ console.log(‘中间件1’); next(); });
app.use(function(req, res, next){ console.log(‘中间件2’); });

1
2
3
4
5
6
7
8
app.use(function(req, res, next){
     console.log(‘中间件1’);
     next();
});
 
app.use(function(req, res, next){
     console.log(‘中间件2’);
});

咱俩加多了两此中间件,央浼过来以往会先被第三个捕获,然后实行拍卖,输出“中间件1”。前面随着施行了next()方法,就能进来下多个中间件。贰此中间件试行后仅有二种采取,要么用next指向下八当中间件,要么将倡议重返。尽管什么都不做,央求将会被挂起,约等于说浏览器端将得不到重返,平素处在pendding状态。举例地点的上游件2,将会招致诉求挂起,那是应该杜绝的。

响应措施

[res.end()] | 终结响应管理流程。 |
[res.redirect()] | 重定向央浼。 |
[res.render()] | 渲染视图模板。 |
[res.send()] | 发送各体系型的响应。 |
[res.sendFile] | 以七人字节流的花样发送文书。 |
可选择 app.route()
创制路由路线的链式路由句柄。由于路径在二个地点钦赐,那样做惹是生非创制模块化的路由,何况减弱了代码冗余和拼写错误。
app.route(‘/book’)
.get(function(req, res) {
res.send(‘Get a random book’);
})
.post(function(req, res) {
res.send(‘Add a book’);
})
.put(function(req, res) {
res.send(‘Update the book’);
});
可利用 express.Router
类创立模块化、可挂载的路由句柄。上边包车型客车实例程序创立了叁个路由模块,并加载了壹在那之中间件,定义了某些路由,並且将它们挂载至采取的门径上。
var express = require(‘express’);
var router = express.Router();
// 该路由运用的中间件
router.use(function timeLog(req, res, next) {
console.log(‘Time: ‘, Date.now());
next();
});
// 定义网址主页的路由
router.get(‘/’, function(req, res) {
res.send(‘Birds home page’);
});
// 定义 about 页面包车型大巴路由
router.get(‘/about’, function(req, res) {
res.send(‘About birds’);
});
module.exports = router;
下一场在运用中加载路由模块:var birds = require(‘./birds’); …
app.use(‘/birds’, birds);

路由设计

运营起了服务器,通晓了中间件编制程序情势,接下去大家就该为前端提供api了。举个例子前端post二个恳求到/api/submitQuestion来交付风度翩翩份数据,大家该怎样选用伏乞并做出管理吧,那便是路由的设计了。

给app.use的第二个参数字传送入路线能够合营到相应的伏乞,举个例子:

JavaScript

app.use(‘/api/submitQuestion’, function(){})

1
app.use(‘/api/submitQuestion’, function(){})

诸有此类就足以捕获到刚刚的交由试题的伸手,在其次个参数中得以实行相应的管理,举例把数量插入到数据库。

不过,要小心了,express路由的没有错行使姿势并非这么的。app.use是用来协作中间件的门径的,并非伸手的门道。因为路由也是生机勃勃种中间件,所以这么的用法也是能够变成效能的,但是咱们依然应该信守官方正式的写法来写。

正规的写法是怎么体统呢?代码如下:

JavaScript

var apiRouter = express.Router(); apiRouter.post(‘/submitQuestion’,
questionController.save); app.use(‘/api’, apiRouter);

1
2
3
var apiRouter = express.Router();
apiRouter.post(‘/submitQuestion’, questionController.save);
app.use(‘/api’, apiRouter);

咱俩利用的是express.Router这几个目标,它同样有use、post、get等形式,用来合营乞求路线。然后大家再利用app.use把apiRouter作为第三个参数字传送进去。

要小心的是apiRouter.post和app.use的率先个参数。app.use相称的是伸手的“根路线”,那样可以把必要分为差异的品类,比如存有的异步接口大家都叫api,那么那类诉求大家就都应有挂在“/api”下。依照那样的平整,大家全部项目标路由法规如下:

JavaScript

//注册路由 app.get(‘/’, function(req, res){
res.sendFile(_rootDir+’/src/index.html’); }); var apiRouter =
express.Router(); apiRouter.post(‘/getQuestion’,
questionController.getQuestion); apiRouter.post(‘/getQuestions’,
questionController.getQuestions); apiRouter.post(‘/submitQuestion’,
questionController.save); apiRouter.post(‘/updateQuestion’,
questionController.update); apiRouter.post(‘/removeQuestion’,
questionController.remove); apiRouter.post(‘/getPapers’,
paperController.getPapers); apiRouter.post(‘/getPaper’,
paperController.getPaper); apiRouter.post(‘/getPaperQuestions’,
paperController.getPaperQuestions); apiRouter.post(‘/submitPaper’,
paperController.save); apiRouter.post(‘/updatePaper’,
paperController.update); apiRouter.post(‘/removePaper’,
paperController.remove); app.use(‘/api’, apiRouter);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//注册路由
app.get(‘/’, function(req, res){
    res.sendFile(_rootDir+’/src/index.html’);
});
 
var apiRouter = express.Router();
apiRouter.post(‘/getQuestion’, questionController.getQuestion);
apiRouter.post(‘/getQuestions’, questionController.getQuestions);
apiRouter.post(‘/submitQuestion’, questionController.save);
apiRouter.post(‘/updateQuestion’, questionController.update);
apiRouter.post(‘/removeQuestion’, questionController.remove);
apiRouter.post(‘/getPapers’, paperController.getPapers);
apiRouter.post(‘/getPaper’, paperController.getPaper);
apiRouter.post(‘/getPaperQuestions’, paperController.getPaperQuestions);
apiRouter.post(‘/submitPaper’, paperController.save);
apiRouter.post(‘/updatePaper’, paperController.update);
apiRouter.post(‘/removePaper’, paperController.remove);
 
app.use(‘/api’, apiRouter);

在router的第贰个参数中,大家传入了questionController.save那样的主意,那是什么样东西呢?怎么有一点MVC的含意呢?对的,我们曾经能够合作到路由了,那服务端的事体逻辑以致数据库访谈等该如何组织代码呢?

中间件

Express是由路由和中间件构成一个的 web 开采框架:从本质上来讲,一个Express 应用正是在调用各样中间件。
中间件Middleware是二个函数,它能够访谈央求对象(request
object卡塔尔国, 响应对象(response
object卡塔尔国, 和 web
应用中处于恳求-响应循环流程中的中间件,日常被命名称叫 next 的变量。
中间件的法力包涵:
-实行别的轮代理公司码。
-修改乞求和响应对象。
-终结需要-响应循环。
-调用仓库中的下壹在那之中间件。
只要当前中间件未有达成须要-响应循环,则必得调用 next()
方法将调节权交给下一个中间件,不然需要就能够挂起。

用“MVC”协会代码

用MVC的结构组织代码当然是白金法规了。express能够用模板引擎来渲染view层,路由体制来组织controller层,不过express并不曾明显规定MVC结构应该怎么样写,而是把自由采纳交给你,本身来协会MVC结构。当然你也能够组织别的格局,譬喻像Java中的“n层架构”。

在本项目中,我们就以文件夹的样式来轻易协会一下。因为大家应用了前面一个模板,所将来端的view层就荒诞不经了,唯有controller和model。看一下连串的目录:

银河官方网站 1

在protect下有四个文件夹controllers和models分别放C和M。大家路由中选择的questionController对象就定义在questionController.js中,来看一下用以保存试题的save方法是何等定义的:

JavaScript

var Question = require(‘../models/question’); module.exports = {
//增添试题 save: function(req, res){ var data = req.body.question;
Question.save(data, function(err, data){ if(err){ res.send({success:
false, error: err}); } else{ res.send({success: true, data: data}); }
}); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var Question = require(‘../models/question’);
module.exports = {
     //添加试题
     save: function(req, res){
          var data = req.body.question;
          Question.save(data, function(err, data){
               if(err){
          res.send({success: false, error: err});
     }
     else{
          res.send({success: true, data: data});
     }
          });
     }
}

questionController作为二个模块,使用专门的学问的commonjs语法,大家定义了save方法,通过req.body.question,能够得到前台传过来的数码。在此个模块中,我们require了坐落model层的Question模型,对的,它就是用来操作数据库的,调用Question.save方法,那份数据就存入了数据库,然后在回调函数中,大家用res.send将json数据重临给前端。

概念好questionController后,咱们就能够在server.js中把它给require进去了,然后就有了前面我们在路由中使用的

JavaScript

apiRouter.post(‘/submitQuestion’, questionController.save);

1
apiRouter.post(‘/submitQuestion’, questionController.save);

成套工艺流程就勾搭起来了。

models文件夹中放的正是模型了,用来保管与数据库的映照和相互,这里运用了mongoose作为数据库的操作工具,model层怎么样来编排,本篇就不做牵线了,在下豆蔻年华篇中我们再详尽疏解。

终极再声称一下,本篇文章的代码是依赖叁个演练项目QuestionMaker,为了越来越好精晓小说中的陈说,请查看项目标源码:

1 赞 2 收藏
评论

银河官方网站 2

应用级中间件

应用级中间件绑定到app对象使用 app.use() 和 app.METHOD()
var app = express();
// 未有挂载路线的中间件,应用的各种诉求都会实行该中间件
app.use(function (req, res, next) {
console.log(‘Time:’, Date.now());
next();
});
// 挂载至 /user/:id 的中间件,任何针对 /user/:id 的倡议都会举行它
app.use(‘/user/:id’, function (req, res, next) {
console.log(‘Request Type:’, req.method);
next();
});
// 路由和句柄函数(中间件系统),管理指向 /user/:id 的 GET 央浼
app.get(‘/user/:id’, function (req, res, next) {
res.send(‘USER’);
});

要是急需在中间件栈中跳过剩余中间件,调用 next(‘route’)
方法将调控权交给下三个路由
// 贰个西路件栈,管理指向 /user/:id 的 GET 央求
app.get(‘/user/:id’, function (req, res, next) {
// 尽管 user id 为 0, 跳到下叁个路由
if (req.params.id == 0) next(‘route’);
// 不然将调控权交给栈中下壹此中间件
else next(); //
}, function (req, res, next) {
// 渲染常规页面
res.render(‘regular’);
});
// 管理 /user/:id, 渲染三个新鲜页面
app.get(‘/user/:id’, function (req, res, next) {
res.render(‘special’);
});

路由级中间件

路由级中间件和应用级中间件相符,只是它绑定的对象为 express.Router()。
var router = express.Router();路由级使用 router.use() 或 router.VERB()
加载。
银河官方网站,var app = express();
var router = express.Router();
// 未有挂载路线的中间件,通过该路由的各类央求都会进行该中间件
router.use(function (req, res, next) {
console.log(‘Time:’, Date.now());
next();
});
// 四个西路件栈,突显别的针对 /user/:id 的 HTTP 恳求的新闻
router.use(‘/user/:id’, function(req, res, next) {
console.log(‘Request URL:’, req.originalUrl);
next();
}, function (req, res, next) {
console.log(‘Request Type:’, req.method);
next();
});
// 四个当中件栈,管理指向 /user/:id 的 GET 供给
router.get(‘/user/:id’, function (req, res, next) {
// 假使 user id 为 0, 跳到下二个路由
if (req.params.id == 0) next(‘route’);
// 担任将调节权交给栈中下三当中间件
else next(); //
}, function (req, res, next) {
// 渲染常规页面
res.render(‘regular’);
});
// 管理 /user/:id, 渲染贰个出奇页面
router.get(‘/user/:id’, function (req, res, next) {
console.log(req.params.id);
res.render(‘special’);
});
// 将路由挂载至选择
app.use(‘/’, router);

错误管理中间件

错误管理中间件有 4 个参数,定义错误管理中间件时必得选择那 4 个参数。
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send(‘Something broke!’);
});

模板引擎

views, 放模板文件的目录,举个例子: app.set(‘views’, ‘./views’)
view engine, 模板引擎,举例: app.set(‘view engine’, ‘jade’)
假定 view engine
设置成功,就没有要求显式钦赐引擎,只怕在应用中加载模板引擎模块,Express
已经在其间加载,即不
app.set(‘view engine’, ‘jade’);
即不用指明视图像和文字件的后缀
app.get(‘/’, function (req, res) {
res.render(‘index’, { title: ‘Hey’, message: ‘Hello there!’});
});

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图