NodeJS旅程 : express - nodejs MVC 中的王牌
正如ASP.NET MVC 在作为.net平台下最佳的 Mvc框架的地位一样,express 在 node.js 环境也有着相同的重要性。在百度上 "nodejs express" 会跑出一大堆关于怎么用开发 express 来开发mvc文章 ,相同的内容在这里我不想重复叙述,关于express的入手文章大家到百度上搜就好了。这只是一篇随笔不是教程, 我是想用ASP.NET MVC与 express 来在他们擅长的方面上做一些比较,从中看看我们作为开发人员能得到什么,哪一个对于我们更能带来好处。
express 与 OWIN
OWIN 全名为:Open Web Interface for .net , 是一套可以让你在IIS中开辟中一套独立运行环境,按需配置模块可独立的应用程序框架。我不知道我的解释是否准确,更多的内容可以参考:"Getting Started with OWIN and Katana" 和 Katan 在Codeplex上的项目。 简单点理解就是你可以通过纯代码,在一个启动文件内配置一些已有的“中间件(middel ware) ” 来配置你的Web的功能。下面来看一段代码,这段代码是从asp.net上截取的,是向网站加入一个 日志的中间件实现日志记录
日志中间件实现
public class LoggerMiddleware : OwinMiddleware { private readonly ILog _logger; public LoggerMiddleware(OwinMiddleware next, ILog logger) : base(next) { _logger = logger; } public override async Task Invoke(IOwinContext context) { _logger.LogInfo("Middleware begin"); await this.Next.Invoke(context); _logger.LogInfo("Middleware end"); } }
启动文件
public class Startup { public void Configuration(IAppBuilder app) { app.Use<LoggerMiddleware>(new TraceLogger()); var config = new HttpConfiguration(); // configure Web API app.UseWebApi(config); // additional middleware registrations } }
到此,如果你是一位MVC开发人员那么请先不要往下看,现在需要一点点的时间给你思考一下,这个东东的意义在哪里,与我们使用的常规MVC有何区别?这个代码跑起来要比运行在MVC快得多得去了,起码IIS不会起动IIS模块加载机制,也不会预编译页面。
我认为OWIN在ASP.NET MVC内是一个很了不起的框架,他可以简化掉现在MVC内很多不必要的模块。这些不必要的模块在让我们的程序变得臃肿、庞大。明明一个小小的Web如果用MVC来做的话,你会发现用php或者直接用ASP.NET PAGES 做会比它快好多。 有可能OWIN是未来ASP.NET MVC版本发展的一个走向,作为开发人员我们有权利确定哪些东西是我们要的,哪些是我们不要的,而不是一股脑地将“强大”的功能塞到我们的项目里面。
接下来我们看看相同的功能在 node.js中是怎么做的,然后大家来评估一下哪个更好:
app.js (express启动的必备文件)
var express = require('express'); var logger = require('morgan'); app.use(logger('dev')); app.listen(3001);
在代码之间对比实际大家在app内写的东西都不多,但值得注意的是express一个成熟的框架,而OWIN是个新生儿。OWIN内做的事都要你自己一个一个地实现,而express内可能只是到npm上找找有哪些好用的模块装一下就完事了。现在asp.net官网上找到的所有关于OWIN的范例在node.js加构下早就有出了名的现成模块了,就好像OAUTH 这个苦B功能,在asp.net上有非常多的内容在说它,你可以试试在express上做,简直就是手至擒来的。
SignalR
说说 SignalR ,关于这个内容开始接触时解得他真的非常赞,但看了google在对 WebRTC 上的技术演示以后就觉得 SignalR 是一个大忽悠。 SignalR实际上只是通过 WebStocket 来做反向通信的一种机制(服务端->客户端)。微软称为 服务器与浏览器的"实时通信",其中的内容并不难实现,但可惜的是WebStocket正在被WebRTC技术所取缔,SignalR 做的一大堆东西我们都可以在 nodejs 下 安装一个非常著名的模块: socket.io 一下搞定,而且socket.io不单可以做到服务器与客户端之间做实时通信,还可以做很多即时通信的功能,功能极其强大!
var app = require('express')(); var server = require('http').Server(app); var io = require('socket.io')(server); io.on('connection', function(){ /* … */ }); server.listen(3000);
这就是一个使用socket.io 在express构建的最简单的通信服务器代码。SignalR的那点事就不想说了,实在连解释它也觉得很累。(^_^ 我是一个很懒很喜欢简单的人)。 建议如果想入手 SignalR 的朋友可以先看看关于 socket.io , 现在的微软与以前不一样了,老鮑将MS玩烂了将很明明很简单的东西都做成了没人愿意用的庞然大物,甚至连我们跟随MS做技术的也同时遭殃。
路由 Routing
我更喜欢 epxress 在Routing的使用,它的定义处理方式都比较简单易懂,而且他更容易获取当前运行的路由对象,用代码说话吧:
var express = require('express'); var router = express.Router(); router.get('/invoice/:id', function(req, res) { var id= req.params.id; ... }).post(function(req,res) { //直接控制POST方法 var postData=req.body; ... });
1. 对参数和的定义会比在ASP.NET中使用正则表达式更简单(当然这里也可以直接写正则表达式)
2. 注意 req.body 这个对象(需要先引入body-parser 模块),这个是由浏览器端Post过来的Form而且已经是一个JSON对象,不像MVC内要搞ODATA才能正常处理JSON
3. 一边定义一边编码,这是我喜欢的。当一个项目中路由多了,这样做的话找起来非常容易。
再回头看看MVC对Router的定义:
首先是RouteConfig.cs (最让人讨厌的是每个 Route都需要有名称!)
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Invoice", action = "Index", id = UrlParameter.Optional } ); } }
然后是:InvoiceController.cs
public class InvoiceController : Controller { public ActionResult Index(int id) { return View(); } }
当我的项目中有超过 50个路由定义,我就要老在找路由与控制的关系....... 苦B啊....
视图引擎
我在ASP.NET MVC项目中基本上不会使用其它的视图引擎,因为觉得没有其它的比Razor更好更快。第一次使用node.js的时候我是有点懵,因为express 上能支持的视图引擎实在是太多了!我认为选择多对开发人员来说并不是一件很实在的大好事,因为对于一个小白的话选谁才是最好的,这个才是一个大难题。 经过一番google, 最后也就找到了它— jade. 与Jade齐名的还有: EJS , CoffeeKup . 最终还是觉得jade的代码量是最少的,最容易懂的。经过一两个小时的阅读与实验基本上就学会了。从代码量来说可以比Razor少上一半,运行速度极高。还有我最喜欢的一点是他可以支持动态编译与输出。这要在Razor做的话那就得实现一个VirtualProvider类将页面嵌入到assembily中才能实现了,过程非常痛苦。这里只想show两段代码,一段是对jade的一瞥,另一段是动态编译页面。(这里我就懒一点了,不帖asp.net MVC的实现了,有兴趣的话你自己可以尝试一下用ASP.NET MVC实现一下,由其是第二步)
看看jade
定一个与asp.net MVC中类似的layout.jade(母板)
doctype html
html
head
title= title
include ./includes/head
link(href="/styles/style.css" , rel="stylesheet")
block head
body.page
block header
block content
block footer
然后搞一个login.jade
extends ../layout
block content
.row
div(class="col-lg-4 col-md-8 col-sm-12 col-lg-centered")
form.text-center(style="padding:20px;")
div
img(src="/logo.png")
p
.input-group
span.ctrl-addon
i.icon-user-3
input#userName(type="text" name="userName" required="required" autofocus="autofocus" placeholder="Enter your user account or email")
p
label
input(type="checkbox" name="rememberMe")
span Remember me
span.pull-right
a Forgot your password?
p
button(class="primary fill-width") Login
div
a.fill-width(role="button") Sign up
对比一下Razor就知道到底少了多少代码。
动态编译 - 动态输出一个能支持markup格式的网页内容
app.use("/dynamic-page/",function(req,res){ var lines=[]; //让引擎直接格式化markup的输出 lines.push("markup:"); lines.push(" **粗体** 字"); lines.push("p."); lines.push(" 这里是一段最为简单的段落文字");
lines.push("#{model.name}") ;
var _fn=jade.compile(lines.join("\n"));
res.send(_fn({ model:{ name:"我是动态编译的上下文对象名" } } ));
在ASP.NET MVC中在Action内动态输出文本绝无问题,但如果要传入一个上下文对象然后再动态编译输出那就是件极痛苦的事了。这个功能由其是在做邮件模板时是非常有用的,我在ASP.NET MVC内只能再找一个动支持Razor语法的类库再重编译输出这个网页内容,这种做法想想都够脑残的。
小结
搞好好几天觉得nodejs+express就是一个字:爽! 而更多关于express的功能我就不在这里说了,大家去官网看吧。如果你有不同的看法或者认为express还有更玄的功能,那就给我留言吧。
相关资源:
安装 : npm install express