>

技术栈开发web应用

- 编辑:至尊游戏网站 -

技术栈开发web应用

用“MEAN”技术栈开采web应用(二)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)是由一个 UEvoqueI(只怕叫路线)和贰个一定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应顾客端对有个别网址节点的拜访。
每多少个路由都能够有八个仍然多少个Computer函数,当相称到路由时,这一个/些函数将被执行。
路由的定义由如下结构重新整合爬山涉水
app.METHOD(PATH, HANDLER)

  • app 是一个 express 实例
  • METHOD 是有些HTTP 诉求形式中的一个
  • PATH 是服务器端的路径
  • HANDLETiggo 是当路由拾贰分到时须求实施的函数
    // 对网站首页的拜见回到 "Hello World!" 字样
    app.get('/', function (req, res) {
    res.send('Hello World!');
    });

// 网址首页接收 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作为第1个参数字传送进去。

要注意的是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!'});
});

本文由技术教程发布,转载请注明来源:技术栈开发web应用