“MEAN”技术栈开发web应用

上一篇我们讲了如何使用angular搭建起项目的前端框架,前端抽象出一个service层来向后端发送请求,后端则返回相应的json数据。本篇我们来介绍一下,如何在nodejs环境下利用express来搭建起服务端,使之正确的响应前端的请求。本文所讲的示例还是基于我们的学习项目QuestionMaker(https://github.com/Double-Lv/QuestionMaker)

运行起基于express的web服务器

express是一个web应用开发框架,它基于nodejs,扩展了很多web开发所需的功能,使得我们能够很方便的访问和操作request和response。请注意它和nginx或者tomcat并不是一个概念,它是一个开发框架,而不是服务器。
运行起基于express的web服务器是非常简单的,因为express都绑你封装好了。首先需要用npm安装好express,然后在项目根目录下新建一个server.js文件,内容如下:
  1. var express = require('express');
  2. var app = express();
  3. app.listen(3000);
  4.  
  5. var _rootDir = __dirname;
  6. var protectDir = _rootDir + '/protect/';
  7.  
  8. app.use(express.static(_rootDir));
  9.  
  10. //注册路由
  11. app.get('/', function(req, res){
  12. res.sendFile(_rootDir+'/src/index.html');
  13. });
  14.  
  15. app.use(function(req, res, next) {
  16. res.status(404).sendFile(_rootDir+'/src/404.html');
  17. });
  18. app.use(function(err, req, res, next) {
  19. console.error(err.stack);
  20. res.status(500).send('500 Error');
  21. });
上述代码实现了这几个功能,首先创建了http服务器,监听在3000端口。
然后app.use(express.static(_rootDir));这一行是使用了静态文件服务的中间件,这样我们项目下的js、css以及图片等静态文件就都可以访问到了。
接下来是注册路由,此处只匹配一个路由规则,那就是"/"(网站的根目录),当匹配到此路由后把首页文件index.html直接用res.sendFile方法给发送到浏览器端。这样浏览器用http://127.0.0.1:3001就可以访问到index.html了。网站的其他页面也可以通过配置类似的路由进行返回。express还支持配置模板引擎,默认支持ejs,你也可以自己配置其他的比如handlebars。
但是在本项目中,我们用的是angular的前端模板,所以后端就不需要模板了,没有进行配置。我们的路由机制也是完全使用的ng的前端路由,所以在express中只配置一条就够了。
在最后还有两块代码,分别是404和500错误的捕获。你可能会疑惑为什么是这样写呢?从上到下排下来就能分别捕获404和500了吗?其实这就是express的中间件机制,在此机制下,对客户端请求的处理像是一个流水线,把所有中间件串联起来,只要某个中间件把请求返回了,就结束执行,否则就从上到下一直处理此请求。
上面代码的流程就是,先按路由规则来匹配路径,如果路由匹配不到,则认为是发生404。500的错误请注意一个细节,在回调函数的参数中,第一个会传入err,就是错误对象,以此来标记是一个500错误。

理解中间件

express的核心是中间件机制,通过使用各种中间件,能够实现灵活的组装我们所需的功能。中间件是在管道中执行的,所谓管道就是像流水线一样,每到达一个加工区,相应的中间件就可以处理request和response对象,处理完后再送往下一个加工区。如果某个加工区把请求终结了,比如调用send方法返回给了客户端,那么处理就终止了。大部分情况下,都有现成的中间件供我们使用,比如用body-parser解析请求实体,用路由(路由也是一种中间件)来正确的派发请求。
比如我们在server.js中添加如下的代码:
  1. app.use(function(req, res, next){
  2. console.log('中间件1');
  3. next();
  4. });
  5.  
  6. app.use(function(req, res, next){
  7. console.log('中间件2');
  8. });

我们添加了两个中间件,请求过来之后会先被第一个捕获,然后进行处理,输出“中间件1”。后面接着执行了next()方法,就会进入下一个中间件。一个中间件执行后只有两种选择,要么用next指向下一个中间件,要么将请求返回。如果什么都不做,请求将会被挂起,也就是说浏览器端将得不到返回,一直处于pendding状态。例如上面的中间件2,将会造成请求挂起,这是应该杜绝的。

 

路由设计

运行起了服务器,了解了中间件编程方式,接下来我们就该为前端提供api了。比如前端post一个请求到/api/submitQuestion来提交一份数据,我们该如何接收请求并做出处理呢,这就是路由的设计了。
给app.use的第一个参数传入路径可以匹配到对应的请求,例如:
  1. app.use('/api/submitQuestion', function(){})
这样就可以捕获到刚刚的提交试题的请求,在第二个参数中可以进行相应的处理,比如把数据插入到数据库。
但是,要注意了,express路由的正确使用姿势并不是这样的。app.use是用来匹配中间件的路径的,而不是请求的路径。因为路由也是一种中间件,所以这样的用法也是能够完成功能的,但是我们还是应该按照官方标准的写法来写。
标准的写法是什么样子呢?代码如下:
  1. var apiRouter = express.Router();
  2. apiRouter.post('/submitQuestion', questionController.save);
  3. app.use('/api', apiRouter);
我们利用的是express.Router这个对象,它同样有use、post、get等方法,用来匹配请求路径。然后我们再使用app.use把apiRouter作为第二个参数传进去。
要注意的是apiRouter.post和app.use的第一个参数。app.use匹配的是请求的“根路径”,这样可以把请求分为不同的类别,比如所有的异步接口我们都叫api,那么这类请求我们就都应该挂在“/api”下。按照这样的规则,我们整个项目的路由规则如下:
  1. //注册路由
  2. app.get('/', function(req, res){
  3. res.sendFile(_rootDir+'/src/index.html');
  4. });
  5.  
  6. var apiRouter = express.Router();
  7. apiRouter.post('/getQuestion', questionController.getQuestion);
  8. apiRouter.post('/getQuestions', questionController.getQuestions);
  9. apiRouter.post('/submitQuestion', questionController.save);
  10. apiRouter.post('/updateQuestion', questionController.update);
  11. apiRouter.post('/removeQuestion', questionController.remove);
  12. apiRouter.post('/getPapers', paperController.getPapers);
  13. apiRouter.post('/getPaper', paperController.getPaper);
  14. apiRouter.post('/getPaperQuestions', paperController.getPaperQuestions);
  15. apiRouter.post('/submitPaper', paperController.save);
  16. apiRouter.post('/updatePaper', paperController.update);
  17. apiRouter.post('/removePaper', paperController.remove);
  18.  
  19. app.use('/api', apiRouter);

在router的第二个参数中,我们传入了questionController.save这样的方法,这是什么东西呢?怎么有点MVC的味道呢?没错,我们已经能够匹配到路由了,那服务端的业务逻辑以及数据库访问等该如何组织代码呢?

用“MVC”组织代码

用MVC的结构组织代码当然是黄金法则了。express可以用模板引擎来渲染view层,路由机制来组织controller层,但是express并没有明确规定MVC结构应该怎样写,而是把自由选择交给你,自己来组织MVC结构。当然你也可以组织别的形式,比如像Java中的“n层架构”。
在本项目中,我们就以文件夹的形式来简单组织一下。因为我们使用了前端模板,所以后端的view层就不存在了,只有controller和model。看一下项目的目录:
在protect下有两个文件夹controllers和models分别放C和M。我们路由中使用的questionController对象就定义在questionController.js中,来看一下用于保存试题的save方法是如何定义的:
  1. var Question = require('../models/question');
  2. module.exports = {
  3. //添加试题
  4. save: function(req, res){
  5. var data = req.body.question;
  6. Question.save(data, function(err, data){
  7. if(err){
  8. res.send({success: false, error: err});
  9. }
  10. else{
  11. res.send({success: true, data: data});
  12. }
  13. });
  14. }
  15. }
questionController作为一个模块,使用标准的commonjs语法,我们定义了save方法,通过req.body.question,可以拿到前台传过来的数据。在这个模块中,我们require了位于model层的Question模型,没错,它就是用来操作数据库的,调用Question.save方法,这份数据就存入了数据库,然后在回调函数中,我们用res.send将json数据返回给前端。
定义好questionController后,我们就可以在server.js中把它给require进去了,然后就有了之前我们在路由中使用的
  1. apiRouter.post('/submitQuestion', questionController.save);
整个流程就串通起来了。
models文件夹中放的就是模型了,用来管理与数据库的映射和交互,这里使用了mongoose作为数据库的操作工具,model层如何来编写,本篇就不做介绍了,在下一篇中我们再详细讲解。
最后再声明一下,本篇文章的代码是基于一个练习项目QuestionMaker,为了更好理解文章中的叙述,请查看项目的源码:https://github.com/Double-Lv/QuestionMaker
 

“MEAN”技术栈开发web应用的更多相关文章

  1. 用“MEAN”技术栈开发web应用(三)用mongodb搭建数据库

    上一篇介绍了如何用express搭建起服务端MVC的开发架构,本篇我们来详细介绍一下这个Model层,也就是数据库访问层.包含如何使用mongodb搭建数据库,以及如何使用mongoose来访问数据. ...

  2. 用“MEAN”技术栈开发web应用(一)AngularJs前端架构

    前言 不知何时突然冒出“MEAN技术栈”这个新词,听起来很牛逼的样子,其实就是我们已经熟悉了的近两年在前端比较流行的技术,mongodb.express.angularjs.nodejs,由于这几项技 ...

  3. 用“MEAN”技术栈开发web应用(二)express搭建服务端框架

    上一篇我们讲了如何使用angular搭建起项目的前端框架,前端抽象出一个service层来向后端发送请求,后端则返回相应的json数据.本篇我们来介绍一下,如何在nodejs环境下利用express来 ...

  4. Spring Security技术栈开发企业级认证与授权(一)环境搭建

    本项目是基于慕课网的Spring Security技术栈开发企业级认证与授权,采用IDEA开发,本文章用来记录该项目的学习过程. 慕课网视频:https://coding.imooc.com/clas ...

  5. web技术栈开发原生应用-多端共用一套代码

    weex: vuejs开发原生应用 nativescript: vuejs开发原生应用 ReactNative = reactjs开发原生应用 ionic = angularjs 开发原生应用

  6. Python全栈开发-web框架之django

    一:web框架 什么是web框架? Web应用框架(Web application framework)是一种开发框架,用来支持动态网站.网络应用程序及网络服务的开发.这种框架有助于减轻网页开发时共通 ...

  7. CefSharp-基于C#的客户端开发框架技术栈开发全记录

    CefSharp简介 源于Google官方 CefSharp用途 CefSharp开发示例 CefSharp应用--弹窗与右键 不弹出子窗体 禁用右键 CefSharp应用--High DPI问题 缩 ...

  8. 【转】android技术栈

    android技术栈-现有使用的进行一个汇总(初稿) 2017年04月24日 16:19:40 阅读数:2004 android技术栈 开发工具 Android studio 开发语言 Java 自动 ...

  9. Web前端开发大系概览 (前端开发技术栈)

    前言 互联网建立50多年了,网站开发技术日新月异,但web前端始终离不开浏览器,最终还是HTML+JavaScript+CSS这3个核心,围绕这3个核心而开发出来大量技术框架/解决方案. 我从2000 ...

随机推荐

  1. c++多态的案例分析

    近期在研究c++中多态的应用 ,当中遇到些许的疑问与问题,可是终于的结果是不容置疑的,以下记录下我的学习过程,以纪念本个知识点. 首先,是从一个案例開始的,题目大意是这种: 设定一个多边形的公共类,然 ...

  2. ASP.NET 成员资格 Part.2(使用安全控件 Login)

    原文:ASP.NET 成员资格 Part.2(使用安全控件 Login)        准备好提供程序以及用户信息的存储,就可以开始构建验证用户.注册用户或者让用户能够重置密码的用户界面了.ASP.N ...

  3. A Game of Thrones(0) - PROLOGUE

    "We should start back", Gared urged as the woods began to grow dark around them. "The ...

  4. 从零开始学Xamarin.Forms(二) 环境搭建、创建项目

    原文:从零开始学Xamarin.Forms(二) 环境搭建.创建项目 一.环境搭建 Windows下环境搭建:     1.下载并安装jdk.Android SDK和NDK,当然还需要 VS2013 ...

  5. jenkins配置.net mvc网站

    jenkins配置.net mvc网站 上一篇使用jenkins配置.net mvc网站进行持续集成一只是简单介绍了jenkins构建站点到本地服务器,这一篇,就来讲解如何部署站点到指定的服务器上面. ...

  6. NYOJ710 外星人的供给站 【贪心】

    外星人的供给站 时间限制:1000 ms  |  内存限制:65535 KB 难度: 描写叙述 外星人指的是地球以外的智慧生命.外星人长的是不是与地球上的人一样并不重要,但起码应该符合我们眼下对生命基 ...

  7. Java实现字符全阵列阵列

    import org.junit.Test; public class AllSort { public void permutation(char[] buf, int start, int end ...

  8. 使用JAVASCRIPT实现静态物体、静态方法和静态属性

    Javascript语言的面向对象特征非常弱.其它面向对象语言在创建类时仅仅要使用keywordstatic就可以指定类为静态类,Javascript没有提供static这种keyword.要让Jav ...

  9. java实现xml文件CRUD

    java删除xml多个节点: 方案1.你直接改动了nodeList.这一般在做循环时是不同意直接这么做的. 你能够尝试在遍历一个list时,在循环体同一时候删除list里的内容,你会得到一个异常.建议 ...

  10. hdoj 2102 A计画 【BFS】

    称号:hdoj 2102 A计画点击打开链接 意甲冠军:文的就不说了.求救出公主所须要的最短时间,所以用广搜. 分析:读题之后不难做,比一般的题目多了一个条件就是能够传送,那么我们能够在广搜里面加一个 ...