如果你想建立轻便,快速,REST API或提供AJAX的强烈丰富的互联网应用,如Gmail服务器支持,或开发可支持数千个并发用户提供方便,给可扩展的系统Node.js的一试。节点,作为其开发者通常把它的简称,是一个服务器端,基于JavaScript的,基于谷歌的高性能V8引擎web服务器,面向接收和回答的HTTP请求。你做你的节点在JavaScript编码,这意味着如果您正在使用的语言客户端编程已经精通,你会在家里使用它为您的服务器端开发感觉。当然,节点超出了客户端JavaScript的能力;它也提供了数据库访问,文件访问,处理分叉,和必要的网络服务职责的一切。
节点是单线程的,事件驱动的服务器;请求处理一次一个,通过一个共同的过程,但你在后台运行任何系统调用,并列,做的时候,这样他们就不会阻塞服务器的处理不同请求的能力触发事件。这类似于nginx的服务器模型,并从,说法不一,阿帕奇的,这是一个多线程服务器;每个请求是由不同的工艺提供服务。随着多个进程也并不重要,如果一个线程需要很长的时间,因为它不会阻止其他进程,但每个进程的高内存需求限制了可能的连接的最大数目。在节点上,你必须要小心,写的代码,将异步运行,这样当一个请求被处理,其他请求可以进来了。用这种方法,节点可以处理数千个并发连接没有conmensurate RAM的要求,因为等待事件需要一些额外的内存。
我们的目标
其中一个最佳使用案例节点是Web服务,因此我们将重温从示例应用程序我Apache和REST Web服务文章,但不是与Apache,PHP和XML的工作中,我们将与节点,JavaScript和JSON(JavaScript对象符号)去。我们将提供相同的国家/地区/城市的网络服务,但我们会成为JSON而不是XML - 虽然你当然可以产生XML输出;看到“增强”侧栏。我们还将指出一些优势,以这种方式工作,缺点这样可以使你是否要使用节点为自己的工作做出明智的决策。
| 回调,延续,并关闭关闭,尤其是因为你用它们来实现节点延续传递风格。有书写延续的许多方面;我在两个不同的方式来表达的替代品写的国家服务。还要注意的getCountries()方法的国家服务,这说明了另外一个问题:想使用一个变量的初始值。闭包可以访问变量本身,所以当你要访问一个循环变量,你总能得到其最终值。您可以使用部分应用程序技术来处理这;检查代码,看看如何。 在Node.js的,你创建的回调函数,并将它们作为参数传递给其他函数,所以当他们完成处理,他们将得到执行。你可能有刷上 |
在我们开始之前,让我们来看看如何节点处理请求:
- 客户端请求的服务。
- 节点接收所述请求。
- 路由代码(你写的)分析请求,并调用适当的功能。
- 该功能做了一些工作,可能调用MySQL的得到一些数据。
- 虽然MySQL的就执行,并行节点服务的其他等待的要求,如果存在的话。
- 当MySQL完成后,一打回来功能被插入在节点队列中,待处理时可能的。
- 在未来的一段时间内,节点运行回调,做一些额外的工作,然后将结果发送回客户端。
据说,在节点,“一切都在并行运行,除了你的代码。”大多数API调用是异步的,也就是说,当你调用的API,你提供一个回调所以当程序完成后,它会调用你的代码以继续处理。节点是不是真的非常适合于CPU密集型的家务(虽然也有,你可以使用一些编码的解决方法),因为它们会阻止系统处理所有其他请求;一个“DIY-DOS”(自己动手拒绝服务)攻击!最后,你必须工作在一个较低的水平比,比如说,Apache和PHP;你必须自己处理HTTP。
编程服务器
要开始使用节点,我们首先要决定如何组织项目。节点提供模块如在独立包装的包裹代码的一种方便的方式。我们router_rest.js模块包含我们的服务器的主要代码,路由到countries_service.js,regions_service.js和cities_service.js模块调用。另外,我们有共同的功能的auxiliar.js模块的所有服务。你应该检查所有从模块我的GitHub库并检查他们,因为我们一起去。
主服务器代码类似于下面的伪代码:
//定义变量来访问每个服务。需要注意的// node.js的模块通过的“规定(......)”电话的使用。VAR的服务= {国家:要求( “./ countries_service ”),地区:要求(“ ./ regions_service ”),城市:要求(“ ./ cities_service”)}功能sendResults(RES,则params,状态,状态文本,标题,导致){//发送HTTP响应,与给定的“状态”的代码和一个//“状态文本”的说明中,“连接:关闭”报头以便//连接不会被保持活,一个“内容类型:应用/ JSON” //标头指定的结果类型,一些可选附加报头,//和结果(如果有的话)在JSON或JSONP格式。}功能routeCall(REQ,RES,体){//分析该URL和请求主体(如果存在的话)和//路径名本身获得查询参数。检查结果是否//将在JSON或JSONP格式的,如果“回调”参数//给出看到。// //如果一个“_method”参数被包括,让它重写//实际HTTP方法。// //分析URL来决定哪些服务电话,如果//现在上面的“服务”阵中,调度呼叫//它,有一个回调指向“sendResults”功能;//否则,返回一个404错误。} process.on( 'uncaughtException',函数(ERR){//提供了意外的异常,因此服务器不会崩溃//通常情况下,报告中的错误。})要求( “HTTP”)。createServer(功能(REQ, res) { // This is the main function, that actually acts as a server // We'll listen on port 8888, just not to interfere with Apache // // For PUT/POST methods, wait until the complete request body // has been read, and then call routeCall. // For GET/DELETE methods, call routeCall directly } }).listen(8888)
获取PUT / POST身体需要编码的是PHP程序员,用于$ _ POST和$ _REQUEST变量,永远不会写了。你必须提供“数据”事件,该事件触发每个服务器获得的HTTP请求主体的额外兼职回调,而另一个回调“结束”事件,当你把所有的正文内容,并可以其火灾移动到路由服务请求。对于bodyless GET / DELETE方法,你可以直接将请求路由。下面的代码总结如下:
如果(req.method === “PUT” || req.method === “POST”){风险体= “”;req.on( “数据”,功能(数据){体+ =数据;});req.on( “结束”,函数(){返回routeCall(REQ,RES,体);});}否则routeCall(REQ,RES, “”);
发送结果仅仅是一个使用writeHead()和end()方法的问题;实际的代码还提供了额外的头,输出端JSONP,但是让我们离开这些细节了,因为他们不增加太多。
标题= {};头[ “连接”] = “关闭”;头[ “内容类型”] = “应用/ JSON”;res.writeHead(状态,状态文本,标头);res.end(JSON.stringify(结果));
最后,错误处理是必须的;没有它,任何错误将与它的所有连接崩溃的服务器。一个域模块是在发展中缓解错误处理,但还不稳定。当你遇到一个错误,至少你应该提供一些日志记录。尽管客户端将不会得到任何答案(并最终得到一个超时错误)至少服务器将继续运行。
编程服务
每个服务将有三个功能:一是为GET通话,另一个用于删除和第三两个PUT和POST请求,这几乎具有相同的逻辑。所有这些服务实际上是相似的;火了一些MySQL的语句,然后处理结果。您在延续风格以避免阻塞其他进程访问MySQL表;您指定要执行的语句,你提供一个回调将被执行时查询的结果是准备和你可以继续处理。例如,要得到所有国家的匹配某些情况下,我写的东西像下面这样:
aux.conn.query( “SELECT * FROM WHERE国家” + someCondition EM>,功能(ERR,行){如果(ERR)//有错误;如果(行它报告给客户端。长度== 0)//没有数据返回发现回调(404, “未找到”); VAR结果= [];对于(VAR i的行)//建立结果[I]与从行数据[I]返回回调(200, “OK”,{},结果);});
| 增强功能xmlbuilder。其它模块,如xml2js和XML的流,可以帮助接受XML输入。 你可以实现很多用普通的Node.js,但许多可用的模块可以帮助你写出更简洁的代码。例如,你可能会串建立你的XML输出字符串,但你可能会更好过一个模块,如 您还可以简化与模块,如路由任务的RESTify,这是更有针对性不是更常见的已知REST Web服务表达模块,或连接,在表达而建,或旅程。 在安全方面,许多模块可以处理认证,如护照,everyauth和连接-AUTH。密码可与加密模块,标准与节点。 对于可扩展性,簇提供了一种工作,多核机器,有几个特点,如正常或硬关机和重新启动服务器,并且每个CPU自动产卵一个工人以获得最佳性能。但是请注意,这个模块仍是试验,那么计划可能发生的变化。 |
MySQL的查询返回包含所有行的数组;也存在着选择,一次处理结果一行。如果没有找到国家,404状态码为宜;否则,遍历行建立一个“结果”数组发送回客户端。如果出现错误,你必须处理它,并发送500个状态码给客户端。
事情变得更加复杂,如果你想返回一个全国所有地区;看看它的源代码。基本上,你必须执行多个MySQL的查询,所有这些更新的“结果”对象在其相应的回调。为了知道你什么时候完成(记住,回调是异步的,在未来,他们的执行顺序无法得到保证),你必须算多少疑问已经准备好,直到计数达到预期数量。看到国家和地区服务,这种设计模式。
DELETE请求很简单:尝试删除相应的记录,看是否产生了一些错误。(如果您的数据模型不包括外键,你必须先尝试删除任何东西之前检查其他表)。如果没有错误,请求成功,所以发回一个204点的状态;否则,分析发生了什么,并提供一个合理的结果代码和状态到客户端:无论是“404 NOT FOUND”或“403不能与城市DELETE区”,如果外键不允许该请求。
PUT和POST请求可以更复杂,因为它们可能涉及INSERT或UPDATE命令。此外,在一些情况下,主密钥将不被给出,并且将改为被MySQL确定;使用“result.insertId”来获得创建的密钥。如果你插入一条记录,你应该返回“201创作的”加一个额外的“位置”标题与新创建的行的REST风格的URI。在错误,返回与适当的解释409点的状态。实际的代码只是一个INSERT尝试,最后是一个UPDATE句子,所以我们不会在这里表现出来。
结论
Node.js的是在积极发展,但尚未在1.0正式版的水平。浏览在线文档显示了一些章节标记为实验性或不稳定的,暗示近期推出的功能,以及正在进行的API的变化可以使生活困难为您服务。但节点是足够稳定是在使用中的公司,如道琼斯,易趣,惠普,LinkedIn,微软,Mozilla的,沃尔玛和Yahoo!考虑所有的利弊,以决定是否部署。对于合适的用途,节点让你把你的JavaScript的经验优势轻松编写RESTful服务。