Node不是万能药!但的确能解决一些关键问题。
学习Node不是一件轻松事儿,但你所收到的回报是对得起你的付出的。由于当下Web应用开发中的诸多难题惟有JavaScript才能解决。 目录
1,专家们的警告! 前端
2,Node:几个小例子
3,Node不是JavaScript,Node能够运行JavaScript node
4,和Node服务器的交互 程序员
5,快速入门手册 web
6,解释器之惑npm
7,基于事件的Web应用 编程
8,Node的用武之地
“你够酷吗?来用我吧!” Node.js 为最新潮的编程语言提供了一系列很酷的API和工具箱,它能够直接应用于传统的Rails、Ajax、Hadoop、甚至能够某种程度上用于iPhone开发和HTML5。若是你参加过一些大型技术会议,你老是会听到一些关于Node.js的主题演讲,尽管这些话题对普通的开发者来讲依然有些难以企及。 你可能已经据说Node.js(有时咱们将其简称为“Node”)是一个服务器端的解决方案,它能够运行JavaScript,并能够做为Web服务来处理HTTP请求。若是这些东东还不至于让你晕头转向的话,转眼间关于端口、sockets和线程的讨论就又成了当下最热门的话题,你会以为这些东西让你眼花缭乱。这些内容真的属于JavaScript的范畴吗?为何世界上那么多人宁愿将JavaScript脱离浏览器而运行,更不用说将JavaScript运行于服务器端了? 好消息是,你所听到的(所想到的)关于Node的一切都是正确的。Node的的确确是属于网络编程的范畴,用以处理服务器端的请求和响应。坏消息是和以前的Rails、Ajax和Hadoop同样,真正实用的技术资料实在太少。等到基于Node的“优秀的”框架成熟以后,技术资料必定会跟得上的,但何须要等到技术书籍和教程都出来以后再去尝试使用Node呢?如今就使用Node,说不定会给你的代码带来意想不到的改观,甚至让你的程序变得更易实现。json
专家门的警告!
和大多数技术同样,Node也是新瓶装旧酒:它看起来不透明并且很怪异,但独受小开发团队的青睐。若是你没有接触过Node,则须要学习一些很容易上手的服务器端脚本。你须要花时间来搞清楚Node,由于即使是运行于服务器端的JavaScript,它和客户端JavaScript也极为不一样。实际状况是,你不得不本身给本身洗脑,以便从新学习理解围绕JavaScript的事件处理机制、异步IO和一些网络基础知识。
不幸的是,这意味着若是你已经用Node做开发超过两年时间的话,你会以为这篇文章内容很单调乏并且过于简单。你会开始寻找新的“刺激”,好比将Node运行于客户端,或者开始尝试事件I/O、反射器模式和npm。你会发现Node的世界是如此有趣,甚至不少Node高级技术具备某种史诗般的美感,而这些东西对于初学者来讲依然是难于企及的。所以,或许你应该将你掌握的知识分享给你的同伴,尤为是对于那些不了解Node的同窗,当他们开始对Node感兴趣时,给他们分享传授Node高级技术。后端
Node:几个小例子
首先,你应当意识到Node是用于运行独立的JavaScript程序的,而不是运行于浏览器中的某个HTML片断里。它是存放在文件系统中的真实存在的文件,由Node程序执行,以一种守护进程的模式运行,同时打开对某些端口的监听。
跳过 hello world
最经典的例子固然是“Hello World“,在Node官网(http://nodejs.org/docs/latest )上有源码。几乎每一个人都是从Hello World开始接触Node的。如今让咱们跳过这个最简单的例子,来看一些更有趣的例子:实现一个能够从服务器发送文件到客户端的程序(而不只仅是发送一段文本到客户端)。
var sys = require("sys"), http = require("http"), url = require("url"), path = require("path"), fs = require("fs");
http.createServer(function(request, response) { var uri = url.parse(request.url).pathname; var filename = path.join(process.cwd(), uri); path.exists(filename, function(exists) { if(!exists) {
response.writeHead(404, {"Content-Type": "text/plain"}); response.end("404 Not Found\n"); return; }
fs.readFile(filename, "binary", function(err, file) { if(err) {
response.writeHead(500, {"Content-Type": "text/plain"}); response.end(err +"\n"); return; }
response.writeHead(200); response.end(file, "binary"); }); });
}).listen(8080);
console.log("Server running at http://localhost:8080/"); 数组
Node不是JavaScript,Node能够运行JavaScript
刚刚你将NodeFileServer.js存成了某个文件,别担忧,咱们等下会回过头来运行它的。如今,让咱们移步到现实当中来,在Unix中执行典型的配置和编译命令:
./configure make
make install
这让咱们确信一个事实:Node不是JavaScript,Node是一个能够运行JavaScript的程序,但Node绝对不是JavaScript。实际上,Node是基于C写的程序。能够经过ls来查看Node/src目录中的文件,能够看到Node的源码:
大多数人会觉得,JavaScript是一门糟糕的语言,更不用说用它来实现服务器端的功能了,其实你只对了一半。不错,对于操做系统级别的Socket和网络编程来讲,JavaScript可能并不能胜任。但Node并非JavaScript实 现的,它是基于C实现的。C语言是能够完美的胜任任意量级的网络编程的。而JavaScript则彻底有能力将指令传递给C程序,而后由C程序来操控操做系统“地下城”。实际上,和C语言相比,JavaScript更容易被开发者们接触到,这是值得引发注意的地方,若是你想用Node进行一些严肃的编程的话,这个缘由会被一再说起。 Node的基本用法进一步反映出了Node是如何和JavaScript一块儿工做的,Node不是JavaScript。你能够经过命令行来运行它:
— (bdm0509@Bretts-MacBook-Pro Sun,29 May 11)
— — — — — — — — — — (/Users/bdm0509/tmp/Node/src) — — (09:09 $)-> export PATH=$HOME/local/Node/bin:$PATH — (bdm0509@Bretts-MacBook-Pro Sun,29 May 11)
— — — — — — — — — — (/Users/bdm0509/tmp/Node/src) — — (09:09 $)-> cd ~/examples
— (bdm0509@Bretts-MacBook-Pro Sun,29 May 11)
— — — — — — — — — — — — (/Users/bdm0509/examples) — — (09:09 $)-> Node NodeFileServer.js Server running at http://127.0.0.1:1337/
这里也不会对此作过多介绍,只要知道Node能够运行JavaScript,这就足够了。并且你只需学习JavaScript这一门编程语言便可,不用担忧本身不懂C语言。记住这是最最重要的一点,没必要了解C也可写出Node可运行的程序。浏览器
和Node服务器的交互
刚才咱们在Node上运行了NodeFileServer.js。这时你能够访问你本机的1337端口,能够看到正常的输出。
请求的服务(这是一个提示,同时打开四个五个甚至十个浏览器访问服务器),这也是很容易作到的。Node让人着迷的地方在于,你彻底能够用很简单并且很不起眼的JavaScript程序来完成你想要的这些结果。
快速入门手册
围绕Node的话题老是会比纯粹运行在服务器端的代码更值得花点时间来讨论。无论怎样,咱们仍是从一段代码开始咱们的话题,概览一下NodeFileServer.js文件,观察代码:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
首先调用了函数require(),require()是程序员最经常使用的函数之一。实际上,在CommonJS规范中也有提到这个函数,在讨论到关于JavaScript模块概念的时候有说起,此外,Davd Flanagan在2009年的一个很酷的实现中也有提到。换句话说,require()对于你来讲多是个新鲜事物,但它不是Node随意添加的一个函数,他是使用JavaScript进行模块化编程的核心概念,Node将这一特性发挥的淋漓尽致。
接下来,http变量用以建立一个服务器。这个服务使用一个回调函数来处理当产生一个链接时的动做。这里的回调函数并未对请求做过多修饰,仅仅以text/plain格式输出一个字符串“Hello World”做为请求响应。这个逻辑很是简单。
实际上,这里展现了使用Node的标准模式:
定义交互类型,并得到一个用以处理这个交互的变量(经过require())。 建立一个新的服务(经过createServer())。
给服务绑定一个回调,用以处理请求。包括处理请求的函数应当包括一个请求…,以及一个响应 通知服务器启动服务,这里须要指定IP和端口(经过listen)。
解释器之惑
尽管经过这种方法可使用JavaScript轻易的实现一个服务(无论运行代码的虚机实际上跑的是C程序仍是其余什么程序),这种作法回避了一个问题:你须要使用JavaScript写出一个服务器吗?为了找到这个问题的答案,咱们来考虑一个很是典型的场景。 JSON的处理
这是一种很是典型的web应用,前台使用HTML和CSS,JavaScript用来做数据验证,并和后台进行数据交互。因为你处于web交互的最顶端,你使用Ajax提交数据到后台并从后台获取数据,而不是单单依靠表单提交来实现。若是你是这样作的话,那么你一样会很是喜欢使用JSON的。JSON是现在最流行的传输数据的格式。 所以,这个Ajax也能够比做“把在线拍卖网站里的某些吉他的信息发给我”。这个请求经过网络到达一个运行PHP程序的服务器。PHP服务器不得不给JavaScript返回不少信息,并且这些信息必须以某种形式的数据包发给客户端,并且这个数据包是能够被JavaScript解析的。所以数据能够打包成数组,而后转换为JSON,就像这样:
$itemGuitar = array( 'id'=>'itemGuitar',
'description'=>'Pete Townshend once played this guitar while his own axe ' . was in the shop having bits of drumkit removed from it.', 'price' => 5695.99,
'urls' => array('http://www.thewho.com', 'http://en.wikipedia.com/wiki/Pete_Townshend') );
$output = json_encode($itemGuitar); print($output);
回到客户端,JavaScript获得这个返回的数据包,因为通过转换,数据编程了JSON格式。就像这样:
{
"id": "itemGuitar",
"description": "Pete Townshend once played this guitar...", "price": 5695.99,
"urls": ["http://www.thewho.com", "http://en.wikipedia.com/wiki/Pete_Townshend"] }
这种转换是标准的,转换先后也是相互等价的。接下来,就能够将这个字符串转换为JavaScript对象,能够调用eval(),就像这样:
var itemDetails = eval('('+ jsonDataString +')');
计算结果是一个普通的JavaScript对象,这个对象的属性和JSON数组的数据结构保持一致。固然,因为jsonDataString一般是由服务器返回的,一般须要这样来解析返回结果:
var itemDetails = eval('('+ request.responseText +')');
这就是最最典型的JSON处理,但存在一个很是严重的问题。 对实体代码微妙的破坏性
(译注:这个小标题着实让人费解,做者这里拐弯抹角的解释了Node的一个好处,就是前端和后端都采用一样的语言JavaScript,在做JSON解析时是无障碍的,而当前端使用JavaScript做JSON编码,后台用PHP做JSON解码时,多少会由于多种语言的JSON解析的实现不一样而带来一些兼容性问题)
首先,这类代码的一个主要问题是,它对解释器的依赖比较严重。在上个例子中,解释器就是指内置的JSON解析器或者实现解析JSON的代码,这实际上依赖了两样东西:和eval()解析响应文本的操做同样的基于Java的JSON解析器,以及基于PHP的JSON解析器。在PHP5.2.0中已经包含了JSON解析器,但倒是之外部依赖的形式给出的,并非内置于PHP的内核中。
但这并非大肆宣扬解释器的种种。毕竟解释器自己还存在不少问题,好比将“I”解析成了“i”,数组中的元素1解释成了2。固然,在JSON工具正式发布以前会有大量的测试,以保证在各类复杂场景中都不会出现错误,包括在客户端的解析结果和在服务器端的解析结果彻底一致。不管如何,这都须要大量的测试才行。 无论怎样,JSON依然存在不少实际的问题。
基于某种语言(基于JavaScript或者PHP)的JSON解析器选择是一个很大的问题。换句话说,问题不是在于“翻译”(translation)而在于“翻译器”(translator)(译注:做者的意思是说JSON自己的规则没有问题,反却是各类语言的JSON实现的质量良莠不齐,甚至有不少bug)。当一个语言的版本比较稳定时,基于这门语言的JSON解析器的运用和推广会比较快。结果是,JSON解析器变的愈来愈强大,以致于能够解析任意复杂的数据结构,即使这么复杂的数据结构根本不会实际用到。反之,每次迭代中(每次计算迭代的路径和数据类型的组合),也颇有可能出现JSON解释器没法解析的数据结构(或者很深的JSON路径)的状况
JavaScript中eval()的潜在隐患
正如咱们不用将Node看成一门新的语言来对待同样,在Node中经过eval()来执行一段代码也和JavaScript中的eval()同样(不被推荐)。众所周知eval()是很是危险的。eval()用以执行一段文本表示的代码逻辑,能够理解为在文本框中“直接敲入SQL代码来执行查询”,这是不安全的,这其实是恶意SQL注入。当每次eval()执行一段字符串的时候,(美国)中西部的一只小狗都会瑟瑟发抖,东部海滩上的某位母亲的脚趾会被刺伤并受到诅咒。
eval()很是危险。网上有不少关于此的资料,这里再也不赘述。能够用google查询“eval JavaScript evil”或者“eval JavaScript injection”获取更多信息。 固然,若是没有任何其余上下文的约束,在Node中也是容许使用eval()的,所以eval()的隐患在Node依然存在。毕竟Node的目的并非彻底解决eval()的问题。Node被称之为基于事件的JavaScript或基于事件的I/O,这里所说的“基于事件”是Node中很是重要的概念。但要完全理解什么是基于事件,以及为何基于事件能让你规避eval()的危险,则须要理解JSON在应用之中是如何工做的,此外还要搞清楚适应于web应用典型架构的特有数据结构。