《写给PHP开发者的Node.js学习指南》一2.2 预定义的PHP变量

2.2 预定义的PHP变量

写给PHP开发者的Node.js学习指南
当一个支持PHP的Web服务器执行一个PHP页面时,它并不是仅提供一个未处理的对某个页面的HTTP request,然后执行这个页面。如果它这样做的话,那么每一个PHP页面都需要大量额外的代码来解析原始的HTTP request并且把这些值用更方便的方式存储起来。相反,PHP引擎解码原始的HTTP请求,并将数据填充到一堆众所周知的PHP全局变量中。这些全局变量被正确填充才能保证PHP页面正常工作。

由于我们采用的基本方法是将PHP页面拷贝到本地模块中并将其转换成Node.js代码,那么我们需要自己在Node.js中实现这些全局变量以保证转换过的页面能正常工作。通过分析PHP页面,我们可以决定它依赖于哪些变量。并不是每一个PHP引擎提供的全局变量都需要实现。相反,我们仅实现那些被使用的到的变量。

有五个PHP预定义的全局变量是最常用的:$_GET、$_POST、$_COOKIE、$_REQUEST和$_SESSION。

一个HTTP request被发送时总是有一个HTTP操作,它被叫作方法或者动词。一个HTTP GET操作是非常简单的:客户端向服务器请求获取一个页面。当用户在浏览器的地址栏里键入URL时,他就是在输入一个HTTP GET request。

HTTP GET request可能有一些以名称/值对形式的参数。这些参数通常叫做查询参数或者查询字符串。用户可以手动向浏览器的地址栏中的URL最后添加添加一个问号(?)并将名称/值对以&符号分割添加到后面。键值对本身之间以等号分割。这有一个例子:

在这个例子中的键值对有:theme=green、tab=users和fastload=true。当一个PHP页面获取到一个像这个例子中一样的GET request时,PHP引擎从原始HTTP GET request中提取出这些键值对并把它们放到预定义的PHP$_GET数组。名字作为$_GET数组中的键值或索引,值就是值。对于之前的URL例子,$_GET数组看起来就像这样:

当PHP页面被转换成Node.js代码后,Node.js仍然需要这些预定义的数组存在并被正确填充。接下来的代码展示了一个Node.js函数 initGET(),它可以被用在任何转换过的PHP页面的本地模块中用来填充一个Node.js_GET变量,这个变量就像PHP中的$_GET变量一样工作:

Node.js函数initGET()需要三个参数:req、pre和cb。req参数包含一个原始的HTTP request。pre参数是一个包含了所有预定义的全局变量的Node.js对象。所有预定义的变量都存储在pre变量中,而不是一堆不同的变量,这样可以方便地传递它。而cb包含了一个在initGET()函数结束时会被调用的回调函数。由于initGET()函数仅进行了一些简单的内存操作并且无需进行有回调函数的操作,因此在技术上并不需要回调函数。但是,由于稍后将要实现的initPOST()函数将会需要一个回调函数cb()作为参数,所以最好让initGET()和initPOST()函数保持一致。

initGET()函数的第一行代码在参数pre中创建了一个名为_GET的数组。pre._GET 就是相当于PHP中$_GET数组的Node.js对象。接下来再从main URL中提取出查询参数,而这个main URL则是从req.url属性获取的。通过使用split()函数来将每一个URL查询参数分离开来进而区分它们的名字/值对使得填充pre._GET变量也非常简单。最后,调用cb参数让回调函数知道pre._GET变量已经可用。

为了初始化Node.js pre._GET变量,需要对exports.serve()函数进行一些修改。这里是最初的exports.serve()函数:

这里我们并不是在exports.serve()函数中实现真实的页面,而是使用一个新的函数叫作page(),exports.serve()将被保留作为初始化和完成其他PHP引擎为PHP页面做的工作:

page()函数需要四个参数:req、res、pre和cb。req和res参数代表HTTP request和HTTP response。pre参数是预定义的变量,包含了存储查询参数的_GET属性。cb参数是一个回调函数,它可以让exports.serve()函数知道什么时候页面被完全处理完了。

将pre对象打印出来可以帮助调试。通过使用require()函数加载内建的util模块,并在res.end()函数调用中添加一个util.inspect()函数调用就可以把pre变量中包括_GET属性的所有内容显示在HTTP response中:

现在处理页面的操作已经移动到page()函数中了,exports.serve()函数被修改成进行初始化工作,包括调用initGET()函数:

pre变量是最先被创建的。然后调用initGET()函数,当它完成时,则调用page()函数。在page()函数之后并没有终止化或清除操作,所以它的回调函数是空的。

当_GET属性被实现之后,就可以修改page()函数使用查询参数。修改page()函数,期待接收一个x查询参数并返回对应的值:

如果Node.js服务器正在运行,并且浏览器被指向到http://localhost: 1337/index.php?x=4,浏览器会显示“The value of x is 4.”。

HTTP POST request和HTTP GET request基本一样,除了键值对是通过request正文而不是URL最后的查询字符串进行发送的。一个HTTP request包括HTTP header和一个HTTP body。包含查询字符串的URL便是HTTP header中的一个。HTTP header内容精简并且有长度限制的。尤其是包含查询字符串的URL,需要限制在一定长度,不推荐使用过长的URL。相应地,当需要在HTTP request中包含很多数据时,推荐把数据放到HTTP body中作为HTTP POST的一部分。HTTP body跟被限制长度的HTTP header不一样,它可以处理非常大量的数据。对于HTTP POST,HTTP body通常被称为POST数据。

由于HTTP POST中的正文可能非常巨大,所以POST数据通常不是一次性发送的;它在收到变成可用的事件时会被发送。事件是Node.js用来指示某件事情发生的一种方法。例如,一个data事件表明下一个数据块已经从HTTP body中被读出。假如这里有很多数据,Node.js会在读取每一块数据时触发若干事件。

一个时间可以跟回调函数联系到一起,这也被叫作事件处理程序。事件处理程序会在一个事件发生时被执行。

on()函数可以将一个事件和事件处理函数联系到一起。下面的例子说明了如何使用on函数把data事件跟一个数据处理函数绑定在一起,这个数据处理函数会将数据写到控制台:

对于initPOST()函数,pre的_POST属性会被初始化。就像从initGET()函数中重新调用后一样,pre参数是一个包含了所有预定义的全局变量的Node.js对象。一个body变量会被创建出来保存到被读取的HTTP body。on()函数把一个事件处理程序和data事件联系到一起,这个事件处理程序会在数据变为可用之后将其写入到body变量中:

在data事件处理程序中添加的if语句是用来检测HTTP正文是否太长,如果是则会中断连接。写得不好或恶意的客户端可能会发送无限量的数据,在这时该if语句就需要放弃那个发送的大量数据的HTTP request来保护Node.js服务器。

最后,on()函数为end事件绑定一个事件处理程序,它会在整个HTTP正文被读取之后触发。通过简单的split()函数调用,end事件处理程序提取出数据并把它们放到pre._POST变量中:

cb()在最后被调用时,已经有正确的pre._POST变量值可以使用了。

将所有代码放到一起,initPOST()函数的全文显示如下:

对于那些期待HTTP GET request的页面,必须修改exports.serve()函数。而对于那些期待HTTP POST request的页面,exports.serve()函数的代码则是一样的,除了调用initGET()函数的地方替换为initPOST()函数调用。设计就是这样的。尽管initGET()函数不需要一个回调函数,但是给initGET()函数一个回调函数让它和initPOST()函数有一样的参数并且代码几乎相同。

到目前为止,HTTP GET和HTTP POST是最常用的HTTP操作,并且在大多数的情况下,这也是一个Web应用程序仅需要的HTTP操作。还有一些其他的HTTP操作,如HTTP PUT、HTTP DELETE和HTTP HEAD,但是PHP引擎并没有对这些操作提供支持,所有Node.js移植通常也不需要提供支持。

cookie是一个服务器发送到客户端(通常是浏览器)的键值对,客户端会将cookie存起来并将它作为一个HTTP header添加到每一个后续的HTTP请求中。客户端通常将cookie存储在一个可持久化的地方,如硬盘中,因此能在将来的HTTP请求中使用这个cookie,即使客户端被关闭并重新启动后。cookie是服务器提供给客户端的一小段数据,它可以帮助服务器验证客户端,例如让客户端可以自动登录自己的账户。

cookie的HTTP header的名字就是“Cookie”:

在Node.js的HTTP请求中,cookies是存储在HTTP请求的headers.cookie属性中的,在本书中的例子里就是req。

initCOOKIE()与initGET()函数都用于将cookie从相应的HTTP头中提取出来并放到pre._COOKIE变量中,非常相似。获取cookie会更方便:cookie不是附加 在URL最后作为查询字符串而是有自己的属性值。pre._COOKIE变量将会 用来替代PHP引擎为PHP页面提供的PHP $_COOKIE变量:

就像那些期待HTTP GET和HTTP POST请求的页面,那些需要cookie的页面需要修改它们的exports.serve()函数来调用initCOOKIE()函数。initCOOKIE()函数跟initGET()和initPOST()有同样的参数,因此可以使用同样的代码调用initCOOKIE()函数:

当一个页面同时需要处理HTTP GET和HTTP POST两种请求并且还需要用到cookie时,可以通过将一个函数当作另一个函数的回调函数的方法来增强exports.serve()函数初始化的操作。以下代码用于加载pre._GET、pre._POST和pre._COOKIE属性,它们将用于替代PHP预定义变量$_GET、$_POST和$_COOKIE:

在PHP里,$_REQUEST预定义变量包含了在$_GET、$_POST和$_COOKIE中所有的键值对。我们需要将pre._GET、pre_POST和pre._COOKIE变量复制一份来创建 pre._REQUEST:

Node.js中的for…in语句可以从一个Node.js对象找出所有的属性名。下面的代码显示了一个对象obj并且把它所有的属性名打印出来:

这里是Node.js的for…in循环的输出:

在PHP中,foreach…as与Node.js中的for…in工作行为差不多,除了foreach…as会返回PHP中的属性值而不是像for…in在Node.js中返回属性名。

就像其他预定义变量的初始化函数一样,initREQUEST()函数必须被exports.serve()函数调用。因为_REQUEST值是_GET、_POST和_COOKIE的一个复合体,构造_REQUEST值需要的三个值已经赋值给pre变量,因此 initREQUEST()函数必须要在其他函数初始化之后被调用:

initREQUEST()函数就像期待的那样与其他初始化函数使用完全相同的参数并且表现也相同。

在PHP还有一个常用的预定义变量:$_SESSION变量。$_SESSION变量代表了每一个用户对 PHP页面的调用。

initSESSION()函数使用pre._COOKIE变量维护当前用户在sessions变量中的会话。当会话不存在时,它会被创建出来;否则,将从sessions对象中获取:

同样也需要让页面处理会话。通过将一个函数添加到另一个函数的回调函数中来加强exports.serve()初始化函数的能力。下面的代码会加载pre._GET、pre._POST、pre._COOKIE和pre._REQUEST属性,它们是用来代替PHP中预定义的变量$_GET、$_POST、$_COOKIE和$_REQUEST的。

initSESSION()函数是在exports.serve()函数中调用的最后一个函数。它依赖于PHP变量$_COOKIE来维护这个会话。为了保证cookie处于被激活的状态,需要修改page()函数的回调函数将cookie返回给调用者:

就像所期待的那样,initSESSION()函数跟其他初始化函数一样采用完全相同的参数,并且执行方式也几乎相同。

这里我们创建一个本地模块initreq.njs用来将initGET()、initPOST()、initCOOKIE()、initREQUEST()和initSESSION()函数共享给所有其他模块。并且这些函数作为属性赋值给exports变量,从而使它们可以暴露给加载该模块的调用者:

为了使用这个initreq.njs本地模块,首先需要用require()函数加载它。然后,需要将模块的名字initreq置于initreq.njs文件暴露出来的每一个初始函数的引用之前来进行调用。下面的代码显示了这些改变:

现在你对于从PHP到Node.js的转换应该有更好的想法并且知道整个过程是如何工作的了。

httpsvr.njs文件是一个Node.js HTTP服务器。在一个常见的PHP设置中,httpsvr.njs文件类似于一个安装了PHP模块的Apache Web服务器。如果你想要调整Node.js Web服务器来添加一些页面,将URL指定到特定的页面或者执行其他通用的Web服务器的配置时,那么就需要修改httpsvr.njs文件。我们把之前的httpsvr.njs例子再放到这里以便于引用:

对于每一个PHP页面,都会有一个index.njs文件或其他模块文件被创建出来。exports.serve()是Node.js中对应于PHP引擎用来处理某个特定页面代码的函数。如果需要一些额外的预定义变量,初始化代码或者结束代码(例如,在页面完成之后执行的代码),就需要修改exports.serve()函数。exports.serve()函数并不是页面本身,而是“包裹”这个页面的代码:

时间: 2024-10-26 10:03:56

《写给PHP开发者的Node.js学习指南》一2.2 预定义的PHP变量的相关文章

《写给PHP开发者的Node.js学习指南》一第 2 章 简单的Node.js框架2.1 HTTP服务器

第 2 章 简单的Node.js框架 写给PHP开发者的Node.js学习指南 在之前的章节,我介绍了一个用于PHP到Node.js转换的开发环境,以及如何使用它进行转换.在本章,我们将开始使用这个开发环境并进行实际的转换. 2.1 HTTP服务器 写给PHP开发者的Node.js学习指南 在PHP中,一个PHP文件代表一个HTML页面.一个Web服务器,比如Apache,当请求一个PHP页面时,Web服务器会运行PHP.但是在Node.js里,Node.js的main文件代表了整个服务器.No

《写给PHP开发者的Node.js学习指南》一导读

前 言 写给PHP开发者的Node.js学习指南 为什么要写这本书呢? 就互联网语言来说,PHP产生于1995年,是一门很古老的语言:而Node.js产生于2009年,是一门非常新的语言.结合PHP和Node.js你可以鸟瞰整个Web服务器从起源到现在的历史过程以及其中的改变.但是更重要的是,这些内容告诉了我们哪些没有改变--没有改变的那些,是整个行业公认的最佳实践--以及一点点未来可能的样子. PHP与Node.js最大的不同在于,PHP是一门阻塞型语言,依赖于API并且在执行结束前并不返回任

《写给PHP开发者的Node.js学习指南》一1.3 Eclipse PDT

1.3 Eclipse PDT 写给PHP开发者的Node.js学习指南学会如何分析堆栈追踪信息是PHP到Node.js成功转换的一个重要技能.堆栈追踪是查找代码错误的一个诊断工具,就像医生用X光来检查病人一样.从某种观点来看,PHP到Node.js的转换可以类似于一个复杂的外科手术.你要对PHP和Node.js代码进行手术.像手术过程一样,转换需要技巧和耐性,但是一个好的环境也有很大帮助.就像手术室中使用X光一样,堆栈追踪就是转换过程中开发环境中的工具.下一步,我们会讨论集成开发环境,为转换过

node.js学习笔记(9) 和谐模式

众所周知,ECMAScript 是一种开放的.国际上广为接受的脚本语言规范. 它本身并不是一种脚本语言.正如在 Web 应用程序中执行有用操作的 bean 集合(例如,Netscape 的 AWT)是 Sun 的 JavaBean 规范的一种实现一样,JavaScript 是 ECMAScript 规范的一种实现. 2015年6月17日,ECMA国际发布了EcmaScript2015,即EcmaScript6(以下简称ES6)草案的正式版.ES6是继ES5之后的一次主要改进,语言规范由ES5.1

Node.js 学习笔记之简介、安装及配置

 本文是Node.js学习笔记系列文章的第一篇,主要给大家讲解的是在Windows和Linux上安装Node.js的方法.软件安装版本以0.12.0为例.希望大家能够喜欢.     简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好. 谁适合阅

《node.js开发指南》观后感

最近在当当网上买了一本<node.js开发指南>,从学习node.js到现在看的第一本中文教程,也算献出了自己处子之身啊,哈哈.前后大约花了4,5个小时通读了node.js部分,附录部分只是略过了,谈一下感想把. 1.本书的定位: 就像书中的前言部分所述,确实是针对node.js还未入门的初学者准备的,但是有一个前提,如果之前没写过像php等后端的语言读本书可能有点迷茫.所以本书的定位人群应该是对后端脚本语言有过一定开发经验,并且熟悉javascript语法的人. 2.本书的组成部分: 个人感

node.js 开发指南 – Node.js 连接 MySQL 并进行数据库操作_node.js

Node.js是一套用来编写高性能网络服务器的JavaScript工具包   通常在NodeJS开发中我们经常涉及到操作数据库,尤其是 MySQL ,作为应用最为广泛的开源数据库则成为我们的首选,本篇就来介绍下如何通过NodeJS来操作 MySQL 数据库. 安装MySQL模块到NodeJS中 我们需要让NodeJS支持MySQL,则需要将MySQL模块添加到系统支持库   想要快速了解Node.js ,赞生推荐亲看看 node.js_guide.pdf  - node.js 开发指南 :想要电

node.js学习笔记(0) 前记

学习笔记原本是从1开始的,然而为了永远"怀念"已经离职的钱童鞋,我决定补上一篇.话说,程序员的数数不都是从0开始的吗. 初识node.js大概是一年前的这个时候,钱童鞋来单位面试,简历上的其中一项技能是node.js.当时我还傻傻的以为又是一个类似jquery的js框架-- 过完年,钱童鞋入职,然后慢慢得熟悉,交流得越来越多,也就慢慢得知node.js的众多优点. google的V8引擎 高速IO 非阻塞 异步回调 单线程 事件驱动 ... 然并卵,吸引我的却是javascript.在

Java开发者结合Node.js编程入门教程_java

首先, 我必须得承认,作为一个有着十多年开发经验的java开发者,我已经形成了解决绝大部分问题的固有套路,尽管它们很多时候显得笨重和繁琐. 比如说如果要读取一个文件,那应该就是初始化一个BufferedReader 实例并传入一个FileReader,这几乎是顺理成章的,我在很多自认为算得上"企业级"的项目中编写这样的代码并且很享受这个过程,可以说我就是一个对其他语言不屑一顾的java脑残粉.      如果你正在阅读这篇博文,你可能已经陷入了我多年前早就陷入的一个误区,作为一名合格的