目录

Node.js - 快速指南

Node.js - Introduction

什么是Node.js?

Node.js是一个基于谷歌Chrome的JavaScript引擎(V8引擎)构建的服务器端平台。 Node.js由Ryan Dahl于2009年开发,其最新版本为v0.10.36。 Node.js的官方文档提供的定义如下 -

Node.js是一个基于Chrome JavaScript运行时的平台,可轻松构建快速,可扩展的网络应用程序。 Node.js使用事件驱动的非阻塞I/O模型,使其轻量级和高效,非常适合在分布式设备上运行的数据密集型实时应用程序。

Node.js是一个开源的跨平台运行时环境,用于开发服务器端和网络应用程序。 Node.js应用程序是用JavaScript编写的,可以在OS X,Microsoft Windows和Linux上的Node.js运行时中运行。

Node.js还提供了各种JavaScript模块的丰富库,它在很大程度上简化了使用Node.js的Web应用程序的开发。

Node.js = Runtime Environment + JavaScript Library

Node.js的功能

以下是使Node.js成为软件架构师首选的一些重要功能。

  • Asynchronous and Event Driven - Node.js库的所有API都是异步的,即非阻塞的。 它本质上意味着基于Node.js的服务器永远不会等待API返回数据。 服务器在调用它之后移动到下一个API,并且Node.js事件的通知机制帮助服务器从先前的API调用获得响应。

  • Very Fast - 基于谷歌Chrome的V8 JavaScript引擎,Node.js库的代码执行速度非常快。

  • Single Threaded but Highly Scalable - Node.js使用带有事件循环的单线程模型。 事件机制可帮助服务器以非阻塞方式进行响应,并使服务器具有高度可伸缩性,而传统服务器则创建有限的线程来处理请求。 Node.js使用单线程程序,同一程序可以为比Apache HTTP Server等传统服务器提供更多请求的服务。

  • No Buffering - Node.js应用程序从不缓冲任何数据。 这些应用程序只是以块的形式输出数据。

  • License - Node.js在MIT许可证发布

谁使用Node.js?

以下是github wiki上的链接,其中包含使用Node.js的项目,应用程序和公司的详尽列表。 此列表包括eBay,通用电气,GoDaddy,微软,PayPal,Uber,Wikipins,Yahoo!和Yammer等等。

概念 (Concepts)

下图描绘了Node.js的一些重要部分,我们将在后续章节中详细讨论。

Node.js概念

在哪里使用Node.js?

以下是Node.js证明自己是完美技术合作伙伴的领域。

  • I/O绑定应用程序
  • 数据流应用程序
  • 数据密集型实时应用程序(DIRT)
  • 基于JSON API的应用程序
  • 单页应用程序

哪里不使用Node.js?

不建议将Node.js用于CPU密集型应用程序。

Node.js - Environment Setup

Try it Option Online

您真的不需要设置自己的环境来开始学习Node.js. 原因很简单,我们已经在线设置了Node.js环境,这样您就可以在线执行所有可用的示例并通过实践学习。 随意修改任何示例并使用不同的选项检查结果。

使用下面示例代码框(在我们的网站上)右上角提供的Live Demo选项,尝试以下示例 -

/* Hello World! program in Node.js */
console.log("Hello World!");

对于本教程中给出的大多数示例,您将找到Try it选项,因此只需使用它并享受您的学习。

本地环境设置 (Local Environment Setup)

如果您仍然愿意为Node.js设置环境,则需要在计算机上使用以下两个软件:(a)文本编辑器和(b)Node.js二进制可安装程序。

文本编辑器 (Text Editor)

这将用于键入您的程序。 少数编辑器的示例包括Windows Notepad,OS Edit命令,Brief,Epsilon,EMACS和vim或vi。

文本编辑器的名称和版本可能因不同的操作系统而异。 例如,Notepad将在Windows上使用,vim或vi可以在Windows以及Linux或UNIX上使用。

使用编辑器创建的文件称为源文件,包含程序源代码。 Node.js程序的源文件通常以扩展名“ .js ”命名。

在开始编程之前,请确保您有一个文本编辑器,并且您有足够的经验来编写计算机程序,将其保存在文件中,最后执行它。

Node.js运行时

用源文件编写的源代码只是javascript。 Node.js解释器将用于解释和执行您的javascript代码。

Node.js发布是SunOS,Linux,Mac OS X和Windows操作系统的二进制安装程序,具有32位(386)和64位(amd64)x86处理器体系结构。

以下部分将指导您如何在各种操作系统上安装Node.js二进制分发版。

下载Node.js存档

Node.js下载中下载最新版本的Node.js可安装存档文件。 在编写本教程时,以下是不同操作系统上可用的版本。

OS 存档名称
Windowsnode-v6.3.1-x64.msi
Linuxnode-v6.3.1-linux-x86.tar.gz
Macnode-v6.3.1-darwin-x86.tar.gz
SunOSnode-v6.3.1-sunos-x86.tar.gz

在UNIX/Linux/Mac OS X和SunOS上安装

根据您的操作系统体系结构,将存档node-v6.3.1- osname .tar.gz下载并解压缩到/ tmp,最后将提取的文件移动到/ usr/local/nodejs目录中。 例如:

$ cd /tmp
$ wget http://nodejs.org/dist/v6.3.1/node-v6.3.1-linux-x64.tar.gz
$ tar xvfz node-v6.3.1-linux-x64.tar.gz
$ mkdir -p /usr/local/nodejs
$ mv node-v6.3.1-linux-x64/* /usr/local/nodejs

将/ usr/local/nodejs/bin添加到PATH环境变量。

OS output
Linux export PATH = $ PATH:/ usr/local/nodejs/bin
Mac export PATH = $ PATH:/ usr/local/nodejs/bin
FreeBSD export PATH = $ PATH:/ usr/local/nodejs/bin

Installation on Windows

使用MSI文件并按照提示安装Node.js. 默认情况下,安装程序使用C:\Program Files\nodejs中的Node.js分发。 安装程序应在窗口的PATH环境变量中设置C:\Program Files\nodejs\bin目录。 重新启动任何打开命令提示更改才能生效。

验证安装:执行文件

在具有以下代码的计算机(Windows或Linux)上创建名为main.js的js文件。

/* Hello, World! program in node.js */
console.log("Hello, World!")

现在使用Node.js解释器执行main.js文件以查看结果 -

$ node main.js

如果您的安装一切正常,这应该产生以下结果 -

Hello, World!

Node.js - First Application

在创建一个真实的“Hello,World!”之前 使用Node.js的应用程序,让我们看看Node.js应用程序的组件。 Node.js应用程序包含以下三个重要组件 -

  • Import required modules - 我们使用require指令加载Node.js模块。

  • Create server - 一个服务器,它将侦听类似于Apache HTTP Server的客户端请求。

  • Read request and return response - 在前面步骤中创建的服务器将读取客户端发出的HTTP请求,该请求可以是浏览器或控制台并返回响应。

创建Node.js应用程序

第1步 - 导入所需模块

我们使用require指令加载http模块并将返回的HTTP实例存储到http变量中,如下所示 -

var http = require("http");

第2步 - 创建服务器

我们使用创建的http实例并调用http.createServer()方法来创建服务器实例,然后使用与服务器实例关联的listen方法将其绑定到端口8081。 传递一个带参数请求和响应的函数。 编写示例实现以始终返回“Hello World”。

http.createServer(function (request, response) {
   // Send the HTTP header 
   // HTTP Status: 200 : OK
   // Content Type: text/plain
   response.writeHead(200, {'Content-Type': 'text/plain'});
   // Send the response body as "Hello World"
   response.end('Hello World\n');
}).listen(8081);
// Console will print the message
console.log('Server running at http://127.0.0.1:8081/');

上面的代码足以创建一个侦听的HTTP服务器,即等待本地机器上8081端口的请求。

第3步 - 测试请求和响应

让我们将第1步和第2步放在一个名为main.js的文件中,然后启动我们的HTTP服务器,如下所示 -

var http = require("http");
http.createServer(function (request, response) {
   // Send the HTTP header 
   // HTTP Status: 200 : OK
   // Content Type: text/plain
   response.writeHead(200, {'Content-Type': 'text/plain'});
   // Send the response body as "Hello World"
   response.end('Hello World\n');
}).listen(8081);
// Console will print the message
console.log('Server running at http://127.0.0.1:8081/');

现在执行main.js以启动服务器,如下所示 -

$ node main.js

验证输出。 服务器已启动。

Server running at http://127.0.0.1:8081/

向Node.js服务器发出请求

在任何浏览器中打开http://127.0.0.1:8081/并观察以下结果。

Node.js示例

恭喜,您已启动并运行第一个HTTP服务器,它响应端口8081上的所有HTTP请求。

Node.js - REPL Terminal

REPL代表Read Eval Print Loop,它代表一个计算机环境,如Windows控制台或Unix/Linux shell,其中输入命令并且系统以交互模式响应输出。 Node.js或Node捆绑了REPL环境。 它执行以下任务 -

  • Read - 读取用户的输入,将输入解析为JavaScript数据结构,并存储在内存中。

  • Eval - 采用并评估数据结构。

  • Print - 打印结果。

  • Loop - 循环上述命令,直到用户按两次ctrl-c

Node的REPL功能在试验Node.js代码和调试JavaScript代码时非常有用。

在线REPL终端

为了简化您的学习,我们在线建立了一个易于使用的Node.js REPL环境,您可以在其中练习Node.js语法 - 启动Node.js REPL终端

启动REPL

只需在shell/console上运行node而不使用任何参数即可启动REPL,如下所示。

$ node

您将看到REPL命令提示符>您可以在其中键入任何Node.js命令 -

$ node
>

简单的表达

让我们在Node.js REPL命令提示符下尝试一个简单的数学 -

$ node
> 1 + 3
4
> 1 + ( 2 * 3 ) - 4
3
>

使用变量

您可以使用变量来存储值,并像以后任何传统脚本一样打印。 如果未使用var关键字,则该值将存储在变量中并打印。 如果使用var关键字,则存储该值但不打印。 您可以使用console.log()打印变量。

$ node
> x = 10
10
> var y = 10
undefined
> x + y
20
> console.log("Hello World")
Hello World
undefined

多线表达

Node REPL支持类似于JavaScript的多行表达式。 让我们检查下面的do-while循环 -

$ node
> var x = 0
undefined
> do {
   ... x++;
   ... console.log("x: " + x);
   ... } 
while ( x < 5 );
x: 1
x: 2
x: 3
x: 4
x: 5
undefined
>

...在开始括号后按Enter键时自动出现。 节点自动检查表达式的连续性。

下划线变量

您可以使用下划线(_)来获得最后的结果 -

$ node
> var x = 10
undefined
> var y = 20
undefined
> x + y
30
> var sum = _
undefined
> console.log(sum)
30
undefined
>

REPL Commands

  • ctrl + c - 终止当前命令。

  • ctrl + c twice - 终止Node REPL。

  • ctrl + d - 终止节点REPL。

  • Up/Down Keys - 查看命令历史记录并修改以前的命令。

  • tab Keys - 当前命令列表。

  • .help - 所有命令的列表。

  • .break - 退出多行表达式。

  • .clear - 退出多行表达式。

  • .save filename - 将当前的Node REPL会话保存到文件中。

  • .load filename - 在当前节点REPL会话中加载文件内容。

停止REPL

如上所述,您需要使用ctrl-c twice来自Node.js REPL。

$ node
>
(^C again to quit)
>

Node.js - NPM

节点包管理器(NPM)提供两个主要功能 -

  • 可在search.nodejs.org上搜索的node.js包/模块的联机存储库

  • 用于安装Node.js包的命令行实用程序,执行Node.js包的版本管理和依赖关系管理。

在v0.6.3版本之后,NPM捆绑了Node.js可安装程序。 要验证相同,请打开控制台并键入以下命令并查看结果 -

$ npm --version
2.7.1

如果您运行的是旧版本的NPM,则可以很容易地将其更新到最新版本。 只需使用root中的以下命令 -

$ sudo npm install npm -g
/usr/bin/npm -> /usr/lib/node_modules/npm/bin/npm-cli.js
npm@2.7.1 /usr/lib/node_modules/npm

使用NPM安装模块

有一个简单的语法来安装任何Node.js模块 -

$ npm install <Module Name>

例如,以下是安装名为express的着名Node.js Web框架模块的命令 -

$ npm install express

现在您可以在js文件中使用此模块,如下所示 -

var express = require('express');

全局与本地安装

默认情况下,NPM在本地模式下安装任何依赖项。 这里的本地模式是指node_modules目录中的软件包安装,该目录位于存在Node应用程序的文件夹中。 可以通过require()方法访问本地部署的包。 例如,当我们安装express模块​​时,它在安装express模块​​的当前目录中创建了node_modules目录。

$ ls -l
total 0
drwxr-xr-x 3 root root 20 Mar 17 02:23 node_modules

或者,您可以使用npm ls命令列出所有本地安装的模块。

全局安装的包/依赖项存储在系统目录中。 此类依赖项可用于任何node.js的CLI(命令行界面)功能,但不能直接使用Node应用程序中的require()导入。 现在让我们尝试使用全局安装来安装快速模块。

$ npm install express -g

这将产生类似的结果,但模块将全局安装。 这里,第一行显示模块版本及其安装位置。

<b class="notranslate">express@4.12.2 /usr/lib/node_modules/express</b>
├── merge-descriptors@1.0.0
├── utils-merge@1.0.0
├── cookie-signature@1.0.6
├── methods@1.1.1
├── fresh@0.2.4
├── cookie@0.1.2
├── escape-html@1.0.1
├── range-parser@1.0.2
├── content-type@1.0.1
├── finalhandler@0.3.3
├── vary@1.0.0
├── parseurl@1.3.0
├── content-disposition@0.5.0
├── path-to-regexp@0.1.3
├── depd@1.0.0
├── qs@2.3.3
├── on-finished@2.2.0 (ee-first@1.1.0)
├── etag@1.5.1 (crc@3.2.1)
├── debug@2.1.3 (ms@0.7.0)
├── proxy-addr@1.0.7 (forwarded@0.1.0, ipaddr.js@0.1.9)
├── send@0.12.1 (destroy@1.0.3, ms@0.7.0, mime@1.3.4)
├── serve-static@1.9.2 (send@0.12.2)
├── accepts@1.2.5 (negotiator@0.5.1, mime-types@2.0.10)
└── type-is@1.6.1 (media-typer@0.3.0, mime-types@2.0.10)

您可以使用以下命令检查全局安装的所有模块 -

$ npm ls -g

Using package.json

package.json存在于任何Node应用程序/模块的根目录中,用于定义包的属性。 让我们打开node_modules/express/的express包的package.json

{
   "name": "express",
      "description": "Fast, unopinionated, minimalist web framework",
      "version": "4.11.2",
      "author": {
         "name": "TJ Holowaychuk",
         "email": "tj@vision-media.ca"
      },
   "contributors": [{
      "name": "Aaron Heckmann",
      "email": "aaron.heckmann+github@gmail.com"
   }, 
   {
      "name": "Ciaran Jessup",
      "email": "ciaranj@gmail.com"
   },
   {
      "name": "Douglas Christopher Wilson",
      "email": "doug@somethingdoug.com"
   },
   {
      "name": "Guillermo Rauch",
      "email": "rauchg@gmail.com"
   },
   {
      "name": "Jonathan Ong",
      "email": "me@jongleberry.com"
   },
   {
      "name": "Roman Shtylman",
      "email": "shtylman+expressjs@gmail.com"
   },
   {
      "name": "Young Jae Sim",
      "email": "hanul@hanul.me"
   } ],
   "license": "MIT", "repository": {
      "type": "git",
      "url": "https://github.com/strongloop/express"
   },
   "homepage": "https://expressjs.com/", "keywords": [
      "express",
      "framework",
      "sinatra",
      "web",
      "rest",
      "restful",
      "router",
      "app",
      "api"
   ],
   "dependencies": {
      "accepts": "~1.2.3",
      "content-disposition": "0.5.0",
      "cookie-signature": "1.0.5",
      "debug": "~2.1.1",
      "depd": "~1.0.0",
      "escape-html": "1.0.1",
      "etag": "~1.5.1",
      "finalhandler": "0.3.3",
      "fresh": "0.2.4",
      "media-typer": "0.3.0",
      "methods": "~1.1.1",
      "on-finished": "~2.2.0",
      "parseurl": "~1.3.0",
      "path-to-regexp": "0.1.3",
      "proxy-addr": "~1.0.6",
      "qs": "2.3.3",
      "range-parser": "~1.0.2",
      "send": "0.11.1",
      "serve-static": "~1.8.1",
      "type-is": "~1.5.6",
      "vary": "~1.0.0",
      "cookie": "0.1.2",
      "merge-descriptors": "0.0.2",
      "utils-merge": "1.0.0"
   },
   "devDependencies": {
      "after": "0.8.1",
      "ejs": "2.1.4",
      "istanbul": "0.3.5",
      "marked": "0.3.3",
      "mocha": "~2.1.0",
      "should": "~4.6.2",
      "supertest": "~0.15.0",
      "hjs": "~0.0.6",
      "body-parser": "~1.11.0",
      "connect-redis": "~2.2.0",
      "cookie-parser": "~1.3.3",
      "express-session": "~1.10.2",
      "jade": "~1.9.1",
      "method-override": "~2.3.1",
      "morgan": "~1.5.1",
      "multiparty": "~4.1.1",
      "vhost": "~3.0.0"
   },
   "engines": {
      "node": ">= 0.10.0"
   },
   "files": [
      "LICENSE",
      "History.md",
      "Readme.md",
      "index.js",
      "lib/"
   ],
   "scripts": {
      "test": "mocha --require test/support/env 
         --reporter spec --bail --check-leaks test/ test/acceptance/",
      "test-cov": "istanbul cover node_modules/mocha/bin/_mocha 
         -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
      "test-tap": "mocha --require test/support/env 
         --reporter tap --check-leaks test/ test/acceptance/",
      "test-travis": "istanbul cover node_modules/mocha/bin/_mocha 
         --report lcovonly -- --require test/support/env 
         --reporter spec --check-leaks test/ test/acceptance/"
   },
   "gitHead": "63ab25579bda70b4927a179b580a9c580b6c7ada",
   "bugs": {
      "url": "https://github.com/strongloop/express/issues"
   },
   "_id": "express@4.11.2",
   "_shasum": "8df3d5a9ac848585f00a0777601823faecd3b148",
   "_from": "express@*",
   "_npmVersion": "1.4.28",
   "_npmUser": {
      "name": "dougwilson",
      "email": "doug@somethingdoug.com"
   },
   "maintainers": [{
      "name": "tjholowaychuk",
      "email": "tj@vision-media.ca"
   },
   {
      "name": "jongleberry",
      "email": "jonathanrichardong@gmail.com"
   },
   {
      "name": "shtylman",
      "email": "shtylman@gmail.com"
   },
   {
      "name": "dougwilson",
      "email": "doug@somethingdoug.com"
   },
   {
      "name": "aredridel",
      "email": "aredridel@nbtsc.org"
   },
   {
      "name": "strongloop",
      "email": "callback@strongloop.com"
   },
   {
      "name": "rfeng",
      "email": "enjoyjava@gmail.com"
   }],
   "dist": {
      "shasum": "8df3d5a9ac848585f00a0777601823faecd3b148",
      "tarball": "https://registry.npmjs.org/express/-/express-4.11.2.tgz"
   },
   "directories": {},
      "_resolved": "https://registry.npmjs.org/express/-/express-4.11.2.tgz",
      "readme": "ERROR: No README data found!"
}

Package.json的属性

  • name - 包的名称

  • version - 包的版本

  • description - 包的描述

  • homepage - 包的主页

  • author - 包的作者

  • contributors - 包的贡献者的名称

  • dependencies - dependencies列表。 NPM会自动在程序包的node_module文件夹中安装此处提到的所有依赖项。

  • repository - 存储库类型和包的URL

  • main - 包裹的入口点

  • keywords - 关键字

卸载模块

使用以下命令卸载Node.js模块。

$ npm uninstall express

NPM卸载软件包后,您可以通过查看/ node_modules /目录的内容来验证它,或者键入以下命令 -

$ npm ls

更新模块

更新package.json并更改要更新的依赖项的版本并运行以下命令。

$ npm update express

搜索模块

使用NPM搜索包名称。

$ npm search express

创建一个模块

创建模块需要生成package.json。 让我们使用NPM生成package.json,它将生成package.json的基本框架。

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.
See 'npm help json' for definitive documentation on these fields
and exactly what they do.
Use 'npm install <pkg> --save' afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (webmaster)

您需要提供有关模块的所有必需信息。 您可以从上面提到的package.json文件中获取帮助,以了解所需的各种信息的含义。 生成package.json后,使用以下命令使用有效的电子邮件地址向NPM存储库站点注册。

$ npm adduser
Username: mcmohd
Password:
Email: (this IS public) mcmohd@gmail.com

是时候发布您的模块了 -

$ npm publish

如果您的模块一切正常,那么它将在存储库中发布,并且可以像使用任何其他Node.js模块一样使用NPM进行安装。

Node.js - Callbacks Concept

什么是回调?

回调是函数的异步等价物。 在给定任务完成时调用回调函数。 Node大量使用回调。 Node的所有API都以支持回调的方式编写。

例如,读取文件的功能可以开始读取文件并立即将控制返回到执行环境,以便可以执行下一条指令。 一旦文件I/O完成,它将在传递回调函数时调用回调函数,该文件的内容作为参数。 因此没有阻塞或等待文件I/O. 这使得Node.js具有高度可扩展性,因为它可以处理大量请求,而无需等待任何函数返回结果。

阻止代码示例

使用以下内容创建名为input.txt的文本文件 -

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

使用以下代码创建名为main.js的js文件 -

var fs = require("fs");
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("Program Ended");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!
Program Ended

非阻塞代码示例

使用以下内容创建名为input.txt的文本文件。

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

更新main.js以获得以下代码 -

var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
   if (err) return console.error(err);
   console.log(data.toString());
});
console.log("Program Ended");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Program Ended
IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

这两个例子解释了阻塞和非阻塞调用的概念。

  • 第一个示例显示程序阻塞,直到它读取文件,然后只有它继续结束程序。

  • 第二个示例显示程序不等待文件读取并继续打印“程序结束”,同时程序无阻塞地继续读取文件。

因此,阻塞程序按顺序执行。 从编程的角度来看,实现逻辑更容易,但非阻塞程序不按顺序执行。 如果程序需要使用任何要处理的数据,则应将其保存在同一块中以使其顺序执行。

Node.js - Event Loop

Node.js是一个单线程应用程序,但它可以通过eventcallbacks的概念支持并发。 Node.js的每个API都是异步的并且是单线程的,它们使用async function calls来维护并发性。 节点使用观察者模式。 节点线程保持事件循环,每当任务完成时,它都会触发相应的事件,该事件表示要执行的事件监听器函数。

Event-Driven Programming

Node.js大量使用事件,这也是Node.js与其他类似技术相比速度非常快的原因之一。 一旦Node启动其服务器,它只需启动其变量,声明函数然后只是等待事件发生。

在事件驱动的应用程序中,通常有一个主循环侦听事件,然后在检测到其中一个事件时触发回调函数。

事件循环

虽然事件看起来与回调非常相似,但不同之处在于,当异步函数返回其结果时调用回调函数,而事件处理对观察者模式起作用。 监听事件的功能充当Observers 。 每当事件被触发时,其侦听器函数就会开始执行。 Node.js通过事件模块和EventEmitter类提供了多个内置事件,这些事件用于绑定事件和事件监听器,如下所示 -

// Import events module
var events = require('events');
// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();

以下是将事件处理程序与事件绑定的语法 -

// Bind event and event  handler as follows
eventEmitter.on('eventName', eventHandler);

我们可以通过以下方式以编程方式触发事件 -

// Fire an event 
eventEmitter.emit('eventName');

例子 (Example)

使用以下代码创建名为main.js的js文件 -

// Import events module
var events = require('events');
// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();
// Create an event handler as follows
var connectHandler = function connected() {
   console.log('connection succesful.');
   // Fire the data_received event 
   eventEmitter.emit('data_received');
}
// Bind the connection event with the handler
eventEmitter.on('connection', connectHandler);
// Bind the data_received event with the anonymous function
eventEmitter.on('data_received', function() {
   console.log('data received succesfully.');
});
// Fire the connection event 
eventEmitter.emit('connection');
console.log("Program Ended.");

现在让我们尝试运行上面的程序并检查其输出 -

$ node main.js

IT应该产生以下结果 -

connection successful.
data received successfully.
Program Ended.

节点应用如何工作?

在节点应用程序中,任何异步函数都接受回调作为最后一个参数,并且回调函数接受错误作为第一个参数。 让我们再次重温上一个例子。 使用以下内容创建名为input.txt的文本文件。

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

使用以下代码创建名为main.js的js文件 -

var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
   if (err) {
      console.log(err.stack);
      return;
   }
   console.log(data.toString());
});
console.log("Program Ended");

这里fs.readFile()是一个异步函数,其目的是读取一个文件。 如果在读取操作期间发生错误,则err object将包含相应的错误,否则数据将包含该文件的内容。 readFile在读取操作完成后将err和数据传递给回调函数,最终打印内容。

Program Ended
IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

Node.js - Event Emitter

Node中的许多对象都会发出事件,例如net.Server每次对等体连接它时都会发出一个事件,fs.readStream会在打开文件时发出事件。 发出事件的所有对象都是events.EventEmitter的实例。

EventEmitter类

正如我们在上一节中看到的,EventEmitter类位于events模块中。 可通过以下代码访问 -

// Import events module
var events = require('events');
// Create an eventEmitter object
var eventEmitter = new events.EventEmitter();

当EventEmitter实例面临任何错误时,它会发出“错误”事件。 添加新侦听器时,会触发“newListener”事件,并且在删除侦听器时会触发“removeListener”事件。

EventEmitter提供了多个属性,如onemiton属性用于将函数绑定到事件,而emit用于触发事件。

方法 (Methods)

Sr.No. 方法和描述
1

addListener(event, listener)

在侦听器数组的末尾为指定的事件添加侦听器。 不进行检查以查看是否已添加监听器。 传递相同的事件和侦听器组合的多个调用将导致多次添加侦听器。 返回发射器,因此可以链接调用。

2

on(event, listener)

在侦听器数组的末尾为指定的事件添加侦听器。 不进行检查以查看是否已添加监听器。 传递相同的事件和侦听器组合的多个调用将导致多次添加侦听器。 返回发射器,因此可以链接调用。

3

once(event, listener)

为事件添加一次性侦听器。 只有在下次触发事件时才会调用此侦听器,之后将其删除。 返回发射器,因此可以链接调用。

4

removeListener(event, listener)

从侦听器数组中删除指定事件的侦听器。 Caution −它更改侦听器后面的侦听器数组中的数组索引。 removeListener最多将从侦听器数组中删除一个侦听器实例。 如果已将多个单个侦听器多次添加到指定事件的侦听器数组,则必须多次调用removeListener以删除每个实例。 返回发射器,因此可以链接调用。

5

removeAllListeners([event])

删除所有侦听器或指定事件的侦听器。 删除代码中其他位置添加的侦听器并不是一个好主意,尤其是当它位于您未创建的发射器上时(例如套接字或文件流)。 返回发射器,因此可以链接调用。

6

setMaxListeners(n)

默认情况下,如果为特定事件添加了10个以上的侦听器,EventEmitters将打印警告。 这是一个有用的默认值,有助于查找内存泄漏。 显然不是所有发射器都应限制在10.此功能允许增加。 设置为零无限制。

7

listeners(event)

返回指定事件的侦听器数组。

8

emit(event, [arg1], [arg2], [...])

使用提供的参数按顺序执行每个侦听器。 如果事件具有侦听器,则返回true,否则返回false。

Class Methods

Sr.No. 方法和描述
1

listenerCount(emitter, event)

返回给定事件的侦听器数。

事件 (Events)

Sr.No. 活动和描述
1

newListener

  • event - 字符串:事件名称

  • listener - 功能:事件处理函数

每次添加侦听器时都会发出此事件。 触发此事件时,可能尚未将侦听器添加到事件的侦听器数组中。

2

removeListener

  • event - String事件名称

  • listener - 功能事件处理函数

任何人删除侦听器时都会发出此事件。 触发此事件时,可能尚未从该事件的侦听器数组中删除侦听器。

例子 (Example)

使用以下Node.js代码创建名为main.js的js文件 -

var events = require('events');
var eventEmitter = new events.EventEmitter();
// listener #1
var listner1 = function listner1() {
   console.log('listner1 executed.');
}
// listener #2
var listner2 = function listner2() {
   console.log('listner2 executed.');
}
// Bind the connection event with the listner1 function
eventEmitter.addListener('connection', listner1);
// Bind the connection event with the listner2 function
eventEmitter.on('connection', listner2);
var eventListeners = require('events').EventEmitter.listenerCount
   (eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");
// Fire the connection event 
eventEmitter.emit('connection');
// Remove the binding of listner1 function
eventEmitter.removeListener('connection', listner1);
console.log("Listner1 will not listen now.");
// Fire the connection event 
eventEmitter.emit('connection');
eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");
console.log("Program Ended.");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

2 Listner(s) listening to connection event
listner1 executed.
listner2 executed.
Listner1 will not listen now.
listner2 executed.
1 Listner(s) listening to connection event
Program Ended.

Node.js - Buffers

纯JavaScript是Unicode友好的,但二进制数据却不是这样。 在处理TCP流或文件系统时,必须处理八位字节流。 Node提供了Buffer类,它提供了存储类似于整数数组的原始数据的实例,但对应于V8堆外部的原始内存分配。

Buffer类是一个全局类,可以在应用程序中访问而无需导入缓冲区模块。

创建缓冲区

节点缓冲区可以以多种方式构建。

Method 1

以下是创建10个八位字节的无启动缓冲区的语法 -

var buf = new Buffer(10);

Method 2

以下是从给定数组创建缓冲区的语法 -

var buf = new Buffer([10, 20, 30, 40, 50]);

方法3 (Method 3)

以下是从给定字符串创建缓冲区的语法,并可选择编码类型 -

var buf = new Buffer("Simply Easy Learning", "utf-8");

虽然“utf8”是默认编码,但您可以使用以下任何编码“ascii”,“utf8”,“utf16le”,“ucs2”,“base64”或“hex”。

写入缓冲区

语法 (Syntax)

以下是写入节点缓冲区的方法的语法 -

buf.write(string[, offset][, length][, encoding])

参数 (Parameters)

以下是所用参数的说明 -

  • string - 这是要写入缓冲区的字符串数据。

  • offset - 这是开始写入的缓冲区的索引。 默认值为0。

  • length - 这是要写入的字节数。 默认为buffer.length。

  • encoding - 要使用的编码。 'utf8'是默认编码。

返回值 (Return Value)

此方法返回写入的八位字节数。 如果缓冲区中没有足够的空间来容纳整个字符串,它将写入字符串的一部分。

例子 (Example)

buf = new Buffer(256);
len = buf.write("Simply Easy Learning");
console.log("Octets written : "+  len);

执行上述程序时,会产生以下结果 -

Octets written : 20

从缓冲区读书

语法 (Syntax)

以下是从节点缓冲区读取数据的方法的语法 -

buf.toString([encoding][, start][, end])

参数 (Parameters)

以下是所用参数的说明 -

  • encoding - 要使用的编码。 'utf8'是默认编码。

  • start - 开始读取的开始索引,默认为0。

  • end - 结束读取的结束索引,默认为完整缓冲区。

返回值 (Return Value)

此方法解码并返回使用指定字符集编码编码的缓冲区数据中的字符串。

例子 (Example)

buf = new Buffer(26);
for (var i = 0 ; i < 26 ; i++) {
  buf[i] = i + 97;
}
console.log( buf.toString('ascii'));       // outputs: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5));   // outputs: abcde
console.log( buf.toString('utf8',0,5));    // outputs: abcde
console.log( buf.toString(undefined,0,5)); // encoding defaults to 'utf8', outputs abcde

执行上述程序时,会产生以下结果 -

abcdefghijklmnopqrstuvwxyz
abcde
abcde
abcde

将Buffer转换为JSON

语法 (Syntax)

以下是将节点缓冲区转换为JSON对象的方法的语法 -

buf.toJSON()

返回值 (Return Value)

此方法返回Buffer实例的JSON表示形式。

例子 (Example)

var buf = new Buffer('Simply Easy Learning');
var json = buf.toJSON(buf);
console.log(json);

执行上述程序时,会产生以下结果 -

{ type: 'Buffer',
   data: 
   [ 
      83,
      105,
      109,
      112,
      108,
      121,
      32,
      69,
      97,
      115,
      121,
      32,
      76,
      101,
      97,
      114,
      110,
      105,
      110,
      103 
   ]
}

连接缓冲区

语法 (Syntax)

以下是将节点缓冲区连接到单个节点缓冲区的方法的语法 -

Buffer.concat(list[, totalLength])

参数 (Parameters)

以下是所用参数的说明 -

  • list - 要连接的Buffer对象的Array列表。

  • totalLength - 这是连接时缓冲区的总长度。

返回值 (Return Value)

此方法返回Buffer实例。

例子 (Example)

var buffer1 = new Buffer('IoWiki ');
var buffer2 = new Buffer('Simply Easy Learning');
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log("buffer3 content: " + buffer3.toString());

执行上述程序时,会产生以下结果 -

buffer3 content: IoWiki Simply Easy Learning

比较缓冲区

语法 (Syntax)

以下是比较两个节点缓冲区的方法的语法 -

buf.compare(otherBuffer);

参数 (Parameters)

以下是所用参数的说明 -

  • otherBuffer - 这是另一个与buf进行比较的buf

返回值 (Return Value)

返回一个数字,指示它是排在顺序之前还是之后,或者与排序顺序中的otherBuffer相同。

例子 (Example)

var buffer1 = new Buffer('ABC');
var buffer2 = new Buffer('ABCD');
var result = buffer1.compare(buffer2);
if(result < 0) {
   console.log(buffer1 +" comes before " + buffer2);
} else if(result === 0) {
   console.log(buffer1 +" is same as " + buffer2);
} else {
   console.log(buffer1 +" comes after " + buffer2);
}

执行上述程序时,会产生以下结果 -

ABC comes before ABCD

复制缓冲区

语法 (Syntax)

以下是复制节点缓冲区的方法的语法 -

buf.copy(targetBuffer[, targetStart][, sourceStart][, sourceEnd])

参数 (Parameters)

以下是所用参数的说明 -

  • targetBuffer - 缓冲区将被复制的缓冲区对象。

  • targetStart - Number,Optional,默认值:0

  • sourceStart - Number,Optional,默认值:0

  • sourceEnd - Number,Optional,默认值:buffer.length

返回值 (Return Value)

没有回报价值。 即使目标存储器区域与源重叠,也要将数据从此缓冲区的区域复制到目标缓冲区中的区域。 如果未定义,则targetStart和sourceStart参数默认为0,而sourceEnd默认为buffer.length。

例子 (Example)

var buffer1 = new Buffer('ABC');
//copy a buffer
var buffer2 = new Buffer(3);
buffer1.copy(buffer2);
console.log("buffer2 content: " + buffer2.toString());

执行上述程序时,会产生以下结果 -

buffer2 content: ABC

切片缓冲液

语法 (Syntax)

以下是获取节点缓冲区的子缓冲区的方法的语法 -

buf.slice([start][, end])

参数 (Parameters)

以下是所用参数的说明 -

  • start - Number,Optional,默认值:0

  • end - Number,Optional,默认值:buffer.length

返回值 (Return Value)

返回一个新的缓冲区,该缓冲区引用与旧的内存相同的内存,但是由start(默认为0)和end(默认为buffer.length)索引进行偏移和裁剪。 负索引从缓冲区的末尾开始。

例子 (Example)

var buffer1 = new Buffer('IoWiki');
//slicing a buffer
var buffer2 = buffer1.slice(0,9);
console.log("buffer2 content: " + buffer2.toString());

执行上述程序时,会产生以下结果 -

buffer2 content: Tutorials

缓冲长度

语法 (Syntax)

以下是获取节点缓冲区大小的方法语法 - 以字节为单位 -

buf.length;

返回值 (Return Value)

以字节为单位返回缓冲区的大小。

例子 (Example)

var buffer = new Buffer('IoWiki');
//length of the buffer
console.log("buffer length: " + buffer.length);

执行上述程序时,会产生以下结果 -

buffer length: 14

方法参考

Class Methods

Sr.No. 方法和描述
1

Buffer.isEncoding(encoding)

如果编码是有效的编码参数,则返回true,否则返回false。

2

Buffer.isBuffer(obj)

测试obj是否为Buffer。

3

Buffer.byteLength(string[, encoding])

给出字符串的实际字节长度。 编码默认为'utf8'。 它与String.prototype.length不同,因为String.prototype.length返回字符串中的字符数。

4

Buffer.concat(list[, totalLength])

返回一个缓冲区,它是将列表中的所有缓冲区连接在一起的结果。

5

Buffer.compare(buf1, buf2)

与buf1.compare(buf2)相同。 用于排序缓冲区数组。

Node.js - Streams

什么是Streams?

流是允许您以连续方式从源读取数据或将数据写入目标的对象。 在Node.js中,有四种类型的流 -

  • Readable - 用于读取操作的流。

  • Writable - 用于写操作的流。

  • Duplex - Stream,可用于读写操作。

  • Transform - 一种双工流,其输出基于输入计算。

每种类型的Stream都是一个EventEmitter实例,并在不同的时间抛出几个事件。 例如,一些常用事件是 -

  • data - 当有数据可供读取时触发此事件。

  • end - 当没有更多数据要读取时,将触发此事件。

  • error - 当接收或写入数据有任何错误时触发此事件。

  • finish - 当所有数据都已刷新到底层系统时触发此事件。

本教程提供了对Streams上常用操作的基本了解。

从溪流中读取

创建一个名为input.txt的文本文件,其中包含以下内容 -

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

使用以下代码创建名为main.js的js文件 -

var fs = require("fs");
var data = '';
// Create a readable stream
var readerStream = fs.createReadStream('input.txt');
// Set the encoding to be utf8. 
readerStream.setEncoding('UTF8');
// Handle stream events --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});
readerStream.on('end',function() {
   console.log(data);
});
readerStream.on('error', function(err) {
   console.log(err.stack);
});
console.log("Program Ended");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Program Ended
IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

写入流

使用以下代码创建名为main.js的js文件 -

var fs = require("fs");
var data = 'Simply Easy Learning';
// Create a writable stream
var writerStream = fs.createWriteStream('output.txt');
// Write the data to stream with encoding to be utf8
writerStream.write(data,'UTF8');
// Mark the end of file
writerStream.end();
// Handle stream events --> finish, and error
writerStream.on('finish', function() {
   console.log("Write completed.");
});
writerStream.on('error', function(err) {
   console.log(err.stack);
});
console.log("Program Ended");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Program Ended
Write completed.

现在打开在当前目录中创建的output.txt; 它应该包含以下内容 -

Simply Easy Learning

管道流

管道是一种机制,我们提供一个流的输出作为另一个流的输入。 它通常用于从一个流中获取数据并将该流的输出传递给另一个流。 管道操作没有限制。 现在我们将展示一个管道示例,用于从一个文件读取并将其写入另一个文件。

使用以下代码创建名为main.js的js文件 -

var fs = require("fs");
// Create a readable stream
var readerStream = fs.createReadStream('input.txt');
// Create a writable stream
var writerStream = fs.createWriteStream('output.txt');
// Pipe the read and write operations
// read input.txt and write data to output.txt
readerStream.pipe(writerStream);
console.log("Program Ended");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Program Ended

打开当前目录中创建的output.txt; 它应该包含以下内容 -

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

链接流

链接是一种将一个流的输出连接到另一个流并创建多个流操作链的机制。 它通常用于管道操作。 现在我们将使用管道和链接来首先压缩文件然后解压缩文件。

使用以下代码创建名为main.js的js文件 -

var fs = require("fs");
var zlib = require('zlib');
// Compress the file input.txt to input.txt.gz
fs.createReadStream('input.txt')
   .pipe(zlib.createGzip())
   .pipe(fs.createWriteStream('input.txt.gz'));
console.log("File Compressed.");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

File Compressed.

您会发现input.txt已被压缩,并在当前目录中创建了一个文件input.txt.gz。 现在让我们尝试使用以下代码解压缩同一个文件 -

var fs = require("fs");
var zlib = require('zlib');
// Decompress the file input.txt.gz to input.txt
fs.createReadStream('input.txt.gz')
   .pipe(zlib.createGunzip())
   .pipe(fs.createWriteStream('input.txt'));
console.log("File Decompressed.");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

File Decompressed.

Node.js - File System

Node使用围绕标准POSIX函数的简单包装器实现文件I/O. 可以使用以下语法导入节点文件系统(fs)模块 -

var fs = require("fs")

同步与异步

fs模块中的每个方法都有同步和异步形式。 异步方法将最后一个参数作为完成函数回调,将回调函数的第一个参数作为错误。 最好使用异步方法而不是同步方法,因为前者在执行期间从不阻塞程序,而第二种方法则执行。

例子 (Example)

使用以下内容创建名为input.txt的文本文件 -

IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

让我们使用以下代码创建一个名为main.js的js文件 -

var fs = require("fs");
// Asynchronous read
fs.readFile('input.txt', function (err, data) {
   if (err) {
      return console.error(err);
   }
   console.log("Asynchronous read: " + data.toString());
});
// Synchronous read
var data = fs.readFileSync('input.txt');
console.log("Synchronous read: " + data.toString());
console.log("Program Ended");

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Synchronous read: IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!
Program Ended
Asynchronous read: IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

本章的以下部分提供了一组关于主要文件I/O方法的优秀示例。

打开文件

语法 (Syntax)

以下是以异步模式打开文件的方法的语法 -

fs.open(path, flags[, mode], callback)

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的文件名的字符串。

  • flags - 标志指示要打开的文件的行为。 下面提到了所有可能的值。

  • mode - 设置文件模式(权限和粘滞位),但仅限于创建文件的情况。 它默认为0666,可读和可写。

  • callback - 这是回调函数,它获取两个参数(err,fd)。

Flags

读/写操作的标志是 -

Sr.No. 标志和描述
1

r

打开文件进行阅读。 如果文件不存在,则会发生异常。

2

r+

打开文件进行读写。 如果文件不存在,则会发生异常。

3

rs

打开文件以便以同步模式读取。

4

rs+

打开文件进行读写,要求操作系统同步打开它。 请参阅“rs”的注释,谨慎使用。

5

w

打开文件进行写作。 创建文件(如果它不存在)或截断(如果存在)。

6

wx

像'w',但如果路径存在则失败。

7

w+

打开文件进行读写。 创建文件(如果它不存在)或截断(如果存在)。

8

wx+

像'w +'但是如果路径存在则失败。

9

a

打开文件进行追加。 如果文件不存在,则创建该文件。

10

ax

像'a',但如果路径存在则失败。

11

a+

打开文件进行阅读和追加。 如果文件不存在,则创建该文件。

12

ax+

像'a +'一样,但如果路径存在则失败。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码,用于打开文件input.txt进行读写。

var fs = require("fs");
// Asynchronous - Opening File
console.log("Going to open file!");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
      return console.error(err);
   }
   console.log("File opened successfully!");     
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to open file!
File opened successfully!

获取文件信息

语法 (Syntax)

以下是获取文件信息的方法的语法 -

fs.stat(path, callback)

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的文件名的字符串。

  • callback - 这是回调函数,它获取两个参数(err,stats),其中stats是fs.Stats类型的对象,在下面的示例中打印。

除了示例中下面打印的重要属性外, fs.Stats类中还有一些有用的方法可用于检查文件类型。 这些方法在下表中给出。

Sr.No. 方法和描述
1

stats.isFile()

如果是简单文件的文件类型,则返回true。

2

stats.isDirectory()

如果目录的文件类型,则返回true。

3

stats.isBlockDevice()

如果块设备的文件类型,则返回true。

4

stats.isCharacterDevice()

如果字符设备的文件类型,则返回true。

5

stats.isSymbolicLink()

如果符号链接的文件类型,则返回true。

6

stats.isFIFO()

如果FIFO的文件类型,则返回true。

7

stats.isSocket()

如果文件类型为asocket,则返回true。

例子 (Example)

让我们使用以下代码创建一个名为main.js的js文件 -

var fs = require("fs");
console.log("Going to get file info!");
fs.stat('input.txt', function (err, stats) {
   if (err) {
      return console.error(err);
   }
   console.log(stats);
   console.log("Got file info successfully!");
   // Check file type
   console.log("isFile ? " + stats.isFile());
   console.log("isDirectory ? " + stats.isDirectory());    
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to get file info!
{ 
   dev: 1792,
   mode: 33188,
   nlink: 1,
   uid: 48,
   gid: 48,
   rdev: 0,
   blksize: 4096,
   ino: 4318127,
   size: 97,
   blocks: 8,
   atime: Sun Mar 22 2015 13:40:00 GMT-0500 (CDT),
   mtime: Sun Mar 22 2015 13:40:57 GMT-0500 (CDT),
   ctime: Sun Mar 22 2015 13:40:57 GMT-0500 (CDT) 
}
Got file info successfully!
isFile ? true
isDirectory ? false

写一个文件 (Writing a File)

语法 (Syntax)

以下是写入文件的方法之一的语法 -

fs.writeFile(filename, data[, options], callback)

如果文件已存在,此方法将覆盖该文件。 如果要写入现有文件,则应使用其他可用方法。

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的文件名的字符串。

  • data - 这是要写入文件的String或Buffer。

  • options - 第三个参数是一个保存{encoding,mode,flag}的对象。 默认情况下。 编码是utf8,模式是八进制值0666.而标志是'w'

  • callback - 这是一个回调函数,它获取一个参数err,在出现任何写入错误时返回错误。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
console.log("Going to write into existing file");
fs.writeFile('input.txt', 'Simply Easy Learning!', function(err) {
   if (err) {
      return console.error(err);
   }
   console.log("Data written successfully!");
   console.log("Let's read newly written data");
   fs.readFile('input.txt', function (err, data) {
      if (err) {
         return console.error(err);
      }
      console.log("Asynchronous read: " + data.toString());
   });
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to write into existing file
Data written successfully!
Let's read newly written data
Asynchronous read: Simply Easy Learning!

Reading a File

语法 (Syntax)

以下是从文件中读取的方法之一的语法 -

fs.read(fd, buffer, offset, length, position, callback)

此方法将使用文件描述符来读取文件。 如果要使用文件名直接读取文件,则应使用其他可用方法。

参数 (Parameters)

以下是所用参数的说明 -

  • fd - 这是fs.open()返回的文件描述符。

  • buffer - 这是将数据写入的缓冲区。

  • offset - 这是缓冲区中开始写入的偏移量。

  • length - 这是一个整数,指定要读取的字节数。

  • position - 这是一个整数,指定从文件中开始读取的位置。 如果position为null,则将从当前文件位置读取数据。

  • callback - 这是回调函数,它获取三个参数,(错误,bytesRead,缓冲区)。

例子 (Example)

让我们使用以下代码创建一个名为main.js的js文件 -

var fs = require("fs");
var buf = new Buffer(1024);
console.log("Going to open an existing file");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
      return console.error(err);
   }
   console.log("File opened successfully!");
   console.log("Going to read the file");
   fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
      if (err){
         console.log(err);
      }
      console.log(bytes + " bytes read");
      // Print only read bytes to avoid junk.
      if(bytes > 0){
         console.log(buf.slice(0, bytes).toString());
      }
   });
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to open an existing file
File opened successfully!
Going to read the file
97 bytes read
IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!

关闭一个文件 (Closing a File)

语法 (Syntax)

以下是关闭打开文件的语法 -

fs.close(fd, callback)

参数 (Parameters)

以下是所用参数的说明 -

  • fd - 这是文件fs.open()方法返回的文件描述符。

  • callback - 这是回调函数除了可能的异常之外,没有给完成回调的参数。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
var buf = new Buffer(1024);
console.log("Going to open an existing file");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
      return console.error(err);
   }
   console.log("File opened successfully!");
   console.log("Going to read the file");
   fs.read(fd, buf, 0, buf.length, 0, function(err, bytes) {
      if (err) {
         console.log(err);
      }
      // Print only read bytes to avoid junk.
      if(bytes > 0) {
         console.log(buf.slice(0, bytes).toString());
      }
      // Close the opened file.
      fs.close(fd, function(err) {
         if (err) {
            console.log(err);
         } 
         console.log("File closed successfully.");
      });
   });
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to open an existing file
File opened successfully!
Going to read the file
IOWIKI is giving self learning content
to teach the world in simple and easy way!!!!!
File closed successfully.

截断文件

语法 (Syntax)

以下是截断打开文件的方法的语法 -

fs.ftruncate(fd, len, callback)

参数 (Parameters)

以下是所用参数的说明 -

  • fd - 这是fs.open()返回的文件描述符。

  • len - 这是文件的长度,之后文件将被截断。

  • callback - 这是回调函数除了可能的异常之外,没有给完成回调的参数。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
var buf = new Buffer(1024);
console.log("Going to open an existing file");
fs.open('input.txt', 'r+', function(err, fd) {
   if (err) {
      return console.error(err);
   }
   console.log("File opened successfully!");
   console.log("Going to truncate the file after 10 bytes");
   // Truncate the opened file.
   fs.ftruncate(fd, 10, function(err) {
      if (err) {
         console.log(err);
      } 
      console.log("File truncated successfully.");
      console.log("Going to read the same file"); 
      fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
         if (err) {
            console.log(err);
         }
         // Print only read bytes to avoid junk.
         if(bytes > 0) {
            console.log(buf.slice(0, bytes).toString());
         }
         // Close the opened file.
         fs.close(fd, function(err) {
            if (err) {
               console.log(err);
            } 
            console.log("File closed successfully.");
         });
      });
   });
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to open an existing file
File opened successfully!
Going to truncate the file after 10 bytes
File truncated successfully.
Going to read the same file
Tutorials 
File closed successfully.

删除文件

语法 (Syntax)

以下是删除文件的方法的语法 -

fs.unlink(path, callback)

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的文件名。

  • callback - 这是回调函数除了可能的异常之外,没有给完成回调的参数。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
console.log("Going to delete an existing file");
fs.unlink('input.txt', function(err) {
   if (err) {
      return console.error(err);
   }
   console.log("File deleted successfully!");
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to delete an existing file
File deleted successfully!

创建目录

语法 (Syntax)

以下是创建目录的方法的语法 -

fs.mkdir(path[, mode], callback)

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的目录名称。

  • mode - 这是要设置的目录权限。 默认为0777。

  • callback - 这是回调函数除了可能的异常之外,没有给完成回调的参数。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
console.log("Going to create directory /tmp/test");
fs.mkdir('/tmp/test',function(err) {
   if (err) {
      return console.error(err);
   }
   console.log("Directory created successfully!");
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to create directory /tmp/test
Directory created successfully!

阅读目录

语法 (Syntax)

以下是读取目录的方法的语法 -

fs.readdir(path, callback)

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的目录名称。

  • callback - 这是回调函数,它获取两个参数(错误,文件),其中files是目录中文件名的数组,不包括'。' 和'..'。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
console.log("Going to read directory /tmp");
fs.readdir("/tmp/",function(err, files) {
   if (err) {
      return console.error(err);
   }
   files.forEach( function (file) {
      console.log( file );
   });
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to read directory /tmp
ccmzx99o.out
ccyCSbkF.out
employee.ser
hsperfdata_apache
test
test.txt

删除目录

语法 (Syntax)

以下是删除目录的方法的语法 -

fs.rmdir(path, callback)

参数 (Parameters)

以下是所用参数的说明 -

  • path - 这是包含路径的目录名称。

  • callback - 这是回调函数除了可能的异常之外,没有给完成回调的参数。

例子 (Example)

让我们创建一个名为main.js的js文件,其中包含以下代码 -

var fs = require("fs");
console.log("Going to delete directory /tmp/test");
fs.rmdir("/tmp/test",function(err) {
   if (err) {
      return console.error(err);
   }
   console.log("Going to read directory /tmp");
   fs.readdir("/tmp/",function(err, files) {
      if (err) {
         return console.error(err);
      }
      files.forEach( function (file) {
         console.log( file );
      });
   });
});

现在运行main.js来查看结果 -

$ node main.js

验证输出。

Going to read directory /tmp
ccmzx99o.out
ccyCSbkF.out
employee.ser
hsperfdata_apache
test.txt

方法参考

Node.js - Global Objects

Node.js全局对象本质上是全局的,并且它们在所有模块中都可用。 我们不需要在我们的应用程序中包含这些对象,而是可以直接使用它们。 这些对象是模块,函数,字符串和对象本身,如下所述。

__filename

__filename表示正在执行的代码的文件名。 这是此代码文件的已解析绝对路径。 对于主程序,这不一定与命令行中使用的文件名相同。 模块内部的值是该模块文件的路径。

例子 (Example)

使用以下代码创建名为main.js的js文件 -

// Let's try to print the value of __filename
console.log( __filename );

现在运行main.js来查看结果 -

$ node main.js

根据您的程序的位置,它将打印主文件名如下 -

/web/com/1427091028_21099/main.js

__dirname

__dirname表示当前正在执行的脚本所在的目录的名称。

例子 (Example)

使用以下代码创建名为main.js的js文件 -

// Let's try to print the value of __dirname
console.log( __dirname );

现在运行main.js来查看结果 -

$ node main.js

根据您的程序的位置,它将打印当前目录名称如下 -

/web/com/1427091028_21099

setTimeout(cb, ms)

setTimeout(cb, ms)全局函数用于在至少ms毫秒后运行回调cb。 实际延迟取决于OS定时器粒度和系统负载等外部因素。 计时器不能超过24.8天。

此函数返回一个不透明值,表示可用于清除计时器的计时器。

例子 (Example)

使用以下代码创建名为main.js的js文件 -

function printHello() {
   console.log( "Hello, World!");
}
// Now call above function after 2 seconds
setTimeout(printHello, 2000);

现在运行main.js来查看结果 -

$ node main.js

确认输出稍有延迟后打印。

Hello, World!

clearTimeout(t)

clearTimeout(t)全局函数用于停止先前使用setTimeout()创建的计时器。 这里t是setTimeout()函数返回的计时器。

例子 (Example)

使用以下代码创建名为main.js的js文件 -

function printHello() {
   console.log( "Hello, World!");
}
// Now call above function after 2 seconds
var t = setTimeout(printHello, 2000);
// Now clear the timer
clearTimeout(t);

现在运行main.js来查看结果 -

$ node main.js

验证输出,您将找不到任何打印的内容。

setInterval(cb, ms)

setInterval(cb, ms)全局函数用于在至少ms毫秒后重复运行回调cb。 实际延迟取决于OS定时器粒度和系统负载等外部因素。 计时器不能超过24.8天。

此函数返回一个不透明值,表示可用于使用clearInterval(t)函数清除计时器的计时器。

例子 (Example)

使用以下代码创建名为main.js的js文件 -

function printHello() {
   console.log( "Hello, World!");
}
// Now call above function after 2 seconds
setInterval(printHello, 2000);

现在运行main.js来查看结果 -

$ node main.js

上述程序将在每2秒后执行printHello()。 由于系统限制。

全球对象

下表提供了我们在应用程序中经常使用的其他对象的列表。 有关更多详细信息,请参阅官方文档。

Sr.No. 模块名称和描述
1 Console

用于在stdout和stderr上打印信息。

2 Process

用于获取有关当前进程的信息。 提供与流程活动相关的多个事件。

Node.js - Utility Modules

Node.js模块库中有几个实用程序模块。 这些模块非常常见,在开发任何基于节点的应用程序时经常使用。

Sr.No. 模块名称和描述
1 OS模块

提供与操作系统相关的基本实用功能。

2 路径模块

提供用于处理和转换文件路径的实用程序。

3 网络模块

提供服务器和客户端作为流。 充当网络包装器。

4 DNS模块

提供执行实际DNS查找以及使用基础操作系统名称解析功能的功能。

5 域模块

提供将多个不同I/O操作作为单个组处理的方法。

Node.js - Web Module

什么是Web服务器?

Web服务器是一种软件应用程序,它处理HTTP客户端(如Web浏览器)发送的HTTP请求,并返回响应客户端的Web页面。 Web服务器通常提供html文档以及图像,样式表和脚本。

大多数Web服务器支持服务器端脚本,使用脚本语言或将任务重定向到应用程序服务器,该应用程序服务器从数据库检索数据并执行复杂逻辑,然后通过Web服务器将结果发送到HTTP客户端。

Apache Web服务器是最常用的Web服务器之一。 这是一个开源项目。

Web应用程序架构

Web应用程序通常分为四层 -

网络架构
  • Client - 该层由Web浏览器,移动浏览器或可向Web服务器发出HTTP请求的应用程序组成。

  • Server - 该层具有Web服务器,可以拦截客户端发出的请求并将响应传递给它们。

  • Business - 该层包含Web服务器用于执行所需处理的应用程序服务器。 该层通过数据库或某些外部程序与数据层交互。

  • Data - 该层包含数据库或任何其他数据源。

使用节点创建Web服务器

Node.js提供了一个http模块,可用于创建服务器的HTTP客户端。 以下是在8081端口侦听的HTTP服务器的最小结构。

创建一个名为server.js的js文件 -

File: server.js

var http = require('http');
var fs = require('fs');
var url = require('url');
// Create a server
http.createServer( function (request, response) {  
   // Parse the request containing file name
   var pathname = url.parse(request.url).pathname;
   // Print the name of the file for which request is made.
   console.log("Request for " + pathname + " received.");
   // Read the requested file content from file system
   fs.readFile(pathname.substr(1), function (err, data) {
      if (err) {
         console.log(err);
         // HTTP Status: 404 : NOT FOUND
         // Content Type: text/plain
         response.writeHead(404, {'Content-Type': 'text/html'});
      } else {	
         //Page found	  
         // HTTP Status: 200 : OK
         // Content Type: text/plain
         response.writeHead(200, {'Content-Type': 'text/html'});	
         // Write the content of the file to response body
         response.write(data.toString());		
      }
      // Send the response body 
      response.end();
   });   
}).listen(8081);
// Console will print the message
console.log('Server running at http://127.0.0.1:8081/');

接下来让我们在您创建server.js的同一目录中创建以下名为index.htm的html文件。

File: index.htm

<html>
   <head>
      <title>Sample Page</title>
   </head>
   <body>
      Hello World!
   </body>
</html>

现在让我们运行server.js来查看结果 -

$ node server.js

验证输出。

Server running at http://127.0.0.1:8081/

向Node.js服务器发出请求

在任何浏览器中打开http://127.0.0.1:8081/index.htm以查看以下结果。

First Server应用程序

验证服务器端的输出。

Server running at http://127.0.0.1:8081/
Request for /index.htm received.

使用Node创建Web客户端

可以使用http模块创建Web客户端。 我们来看看下面的例子。

创建一个名为client.js的js文件 -

File: client.js

var http = require('http');
// Options to be used by request 
var options = {
   host: 'localhost',
   port: '8081',
   path: '/index.htm'  
};
// Callback function is used to deal with response
var callback = function(response) {
   // Continuously update stream with data
   var body = '';
   response.on('data', function(data) {
      body += data;
   });
   response.on('end', function() {
      // Data received completely.
      console.log(body);
   });
}
// Make a request to the server
var req = http.request(options, callback);
req.end();

现在从server.js以外的其他命令终端运行client.js以查看结果 -

$ node client.js

验证输出。

<html>
   <head>
      <title>Sample Page</title>
   </head>
   <body>
      Hello World!
   </body>
</html>

验证服务器端的输出。

Server running at http://127.0.0.1:8081/
Request for /index.htm received.

Node.js - Express Framework

快递概述

Express是一个最小且灵活的Node.js Web应用程序框架,它提供了一组强大的功能来开发Web和移动应用程序。 它有助于基于节点的Web应用程序的快速开发。 以下是Express框架的一些核心功能 -

  • 允许设置中间件以响应HTTP请求。

  • 定义路由表,该表用于基于HTTP方法和URL执行不同的操作。

  • 允许基于将参数传递给模板来动态呈现HTML页面。

安装Express

首先,使用NPM全局安装Express框架,以便可以使用节点终端创建Web应用程序。

$ npm install express --save

上面的命令将本地安装保存在node_modules目录中,并在node_modules内创建一个目录express。 您应该安装以下重要模块以及快递 -

  • body-parser - 这是一个node.js中间件,用于处理JSON,Raw,Text和URL编码的表单数据。

  • cookie-parser - 解析Cookie标头并使用由cookie名称键入的对象填充req.cookies。

  • multer - 这是一个用于处理multipart/form-data的node.js中间件。

$ npm install body-parser --save
$ npm install cookie-parser --save
$ npm install multer --save

Hello,World!的例子

以下是一个非常基本的Express应用程序,它启动服务器并侦听端口8081以进行连接。 这个应用程序响应Hello World! 对主页的请求。 对于其他所有路径,它将以404 Not Found.响应404 Not Found.

var express = require('express');
var app = express();
app.get('/', function (req, res) {
   res.send('Hello World');
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

将上述代码保存在名为server.js的文件中,并使用以下命令运行它。

$ node server.js

您将看到以下输出 -

Example app listening at http://0.0.0.0:8081

在任何浏览器中打开http://127.0.0.1:8081/以查看以下结果。

第一次申请

请求和响应

Express应用程序使用一个回调函数,其参数是requestresponse对象。

app.get('/', function (req, res) {
   // --
})
  • 请求对象 - 请求对象表示HTTP请求,并具有请求查询字符串,参数,正文,HTTP标头等的属性。

  • 响应对象 - 响应对象表示Express应用程序在收到HTTP请求时发送的HTTP响应。

您可以打印reqres对象,这些对象提供与HTTP请求和响应相关的大量信息,包括cookie,会话,URL等。

基本路由

我们已经看到了一个为主页提供HTTP请求的基本应用程序。 路由是指确定应用程序如何响应对特定端点的客户端请求,该请求是URI(或路径)和特定HTTP请求方法(GET,POST等)。

我们将扩展Hello World程序以处理更多类型的HTTP请求。

var express = require('express');
var app = express();
// This responds with "Hello World" on the homepage
app.get('/', function (req, res) {
   console.log("Got a GET request for the homepage");
   res.send('Hello GET');
})
// This responds a POST request for the homepage
app.post('/', function (req, res) {
   console.log("Got a POST request for the homepage");
   res.send('Hello POST');
})
// This responds a DELETE request for the /del_user page.
app.delete('/del_user', function (req, res) {
   console.log("Got a DELETE request for /del_user");
   res.send('Hello DELETE');
})
// This responds a GET request for the /list_user page.
app.get('/list_user', function (req, res) {
   console.log("Got a GET request for /list_user");
   res.send('Page Listing');
})
// This responds a GET request for abcd, abxcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {   
   console.log("Got a GET request for /ab*cd");
   res.send('Page Pattern Match');
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

将上述代码保存在名为server.js的文件中,并使用以下命令运行它。

$ node server.js

您将看到以下输出 -

Example app listening at http://0.0.0.0:8081

现在,您可以在http://127.0.0.1:8081尝试不同的请求,以查看server.js生成的输出。 以下是一些屏幕截图,显示了不同URL的不同响应。

屏幕再次显示http://127.0.0.1:8081/list_user

第二次申请

屏幕再次显示http://127.0.0.1:8081/abcd

第三次申请

屏幕再次显示http://127.0.0.1:8081/abcdefg

第四应用

提供静态文件

Express提供了一个内置的中间件express.static来提供静态文件,例如图像,CSS,JavaScript等。

您只需将保存静态资产的目录名称传递给express.static中间件即可直接开始提供文件。 例如,如果将图像,CSS和JavaScript文件保存在名为public的目录中,则可以执行此操作 -

app.use(express.static('public'));

我们将在public/images子目录中保留一些图像,如下所示 -

node_modules
server.js
public/
public/images
public/images/logo.png

让我们修改“Hello Word”应用程序以添加处理静态文件的功能。

var express = require('express');
var app = express();
app.use(express.static('public'));
app.get('/', function (req, res) {
   res.send('Hello World');
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

将上述代码保存在名为server.js的文件中,并使用以下命令运行它。

$ node server.js

现在在任何浏览器中打开http://127.0.0.1:8081/images/logo.png并查看以下结果。

第五应用

GET方法

这是一个使用HTML FORM GET方法传递两个值的简单示例。 我们将在server.js中使用process_get路由器来处理这个输入。

<html>
   <body>
      <form action = "http://127.0.0.1:8081/process_get" method = "GET">
         First Name: <input type = "text" name = "first_name">  <br>
         Last Name: <input type = "text" name = "last_name">
         <input type = "submit" value = "Submit">
      </form>
   </body>
</html>

让我们在index.htm中保存上面的代码并修改server.js来处理主页请求以及HTML表单发送的输入。

var express = require('express');
var app = express();
app.use(express.static('public'));
app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})
app.get('/process_get', function (req, res) {
   // Prepare output in JSON format
   response = {
      first_name:req.query.first_name,
      last_name:req.query.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

使用http://127.0.0.1:8081/index.htm访问HTML文档将生成以下表单 -

None
名字:
Last Name:

现在您可以输入名字和姓氏,然后单击“提交”按钮查看结果,它应该返回以下结果 -

{"first_name":"John","last_name":"Paul"}

POST Method

这是一个使用HTML FORM POST方法传递两个值的简单示例。 我们将在server.js中使用process_get路由器来处理这个输入。

<html>
   <body>
      <form action = "http://127.0.0.1:8081/process_post" method = "POST">
         First Name: <input type = "text" name = "first_name"> <br>
         Last Name: <input type = "text" name = "last_name">
         <input type = "submit" value = "Submit">
      </form>
   </body>
</html>

让我们在index.htm中保存上面的代码并修改server.js来处理主页请求以及HTML表单发送的输入。

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
// Create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.use(express.static('public'));
app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})
app.post('/process_post', urlencodedParser, function (req, res) {
   // Prepare output in JSON format
   response = {
      first_name:req.body.first_name,
      last_name:req.body.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

使用http://127.0.0.1:8081/index.htm访问HTML文档将生成以下表单 -

None
名字:
Last Name:

现在您可以输入名字和姓氏,然后单击提交按钮以查看以下结果 -

{"first_name":"John","last_name":"Paul"}

上传文件

以下HTML代码创建文件上载器表单。 此表单的方法属性设置为POST ,enctype属性设置为multipart/form-data

<html>
   <head>
      <title>File Uploading Form</title>
   </head>
   <body>
      <h3>File Upload:</h3>
      Select a file to upload: <br />
      <form action = "http://127.0.0.1:8081/file_upload" method = "POST" 
         enctype = "multipart/form-data">
         <input type="file" name="file" size="50" />
         <br />
         <input type = "submit" value = "Upload File" />
      </form>
   </body>
</html>

让我们在index.htm中保存上面的代码并修改server.js来处理主页请求以及文件上传。

var express = require('express');
var app = express();
var fs = require("fs");
var bodyParser = require('body-parser');
var multer  = require('multer');
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}));
app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})
app.post('/file_upload', function (req, res) {
   console.log(req.files.file.name);
   console.log(req.files.file.path);
   console.log(req.files.file.type);
   var file = __dirname + "/" + req.files.file.name;
   fs.readFile( req.files.file.path, function (err, data) {
      fs.writeFile(file, data, function (err) {
         if( err ) {
            console.log( err );
            } else {
               response = {
                  message:'File uploaded successfully',
                  filename:req.files.file.name
               };
            }
         console.log( response );
         res.end( JSON.stringify( response ) );
      });
   });
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

使用http://127.0.0.1:8081/index.htm访问HTML文档将生成以下表单 -

<b class="notranslate">File Upload:</b>
Select a file to upload: 
<input type="file" name="file" size="50">
<input type="button" value="Upload File">
NOTE: This is just dummy form and would not work, but it must work at your server.

Cookies管理

您可以使用以下中间件选项将Cookie发送到Node.js服务器,该服务器可以处理相同的内容。 以下是打印客户端发送的所有cookie的简单示例。

var express      = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get('/', function(req, res) {
   console.log("Cookies: ", req.cookies)
})
app.listen(8081)

Node.js - RESTful API

什么是REST架构?

REST代表REpresentational State Transfer。 REST是基于Web标准的体系结构,使用HTTP协议。 它围绕资源,其中每个组件都是资源,资源由使用HTTP标准方法的公共接口访问。 REST最初由Roy Fielding于2000年推出。

REST服务器只提供对资源和REST客户端访问的访问,并使用HTTP协议修改资源。 这里每个资源都由URI /全局ID标识。 REST使用各种表示来表示文本,JSON,XML等资源,但JSON是最受欢迎的。

HTTP方法

以下四种HTTP方法通常用于基于REST的体系结构。

  • GET - 用于提供对资源的只读访问。

  • PUT - 用于创建新资源。

  • DELETE - 用于删除资源。

  • POST - 用于更新现有资源或创建新资源。

RESTful Web服务

Web服务是用于在应用程序或系统之间交换数据的开放协议和标准的集合。 以各种编程语言编写并在各种平台上运行的软件应用程序可以使用Web服务以类似于因特网的计算机网络以类似于单个计算机上的进程间通信的方式交换数据。 这种互操作性(例如,Java和Python之间的通信,或Windows和Linux应用程序)是由于使用开放标准。

基于REST架构的Web服务称为RESTful Web服务。 这些Web服务使用HTTP方法来实现REST体系结构的概念。 RESTful Web服务通常定义URI,统一资源标识符和服务,它提供资源表示,例如JSON和HTTP方法集。

为库创建RESTful

考虑我们有一个基于JSON的用户数据库,用户在文件users.json中有以下用户:

{
   "user1" : {
      "name" : "mahesh",
      "password" : "password1",
      "profession" : "teacher",
      "id": 1
   },
   "user2" : {
      "name" : "suresh",
      "password" : "password2",
      "profession" : "librarian",
      "id": 2
   },
   "user3" : {
      "name" : "ramesh",
      "password" : "password3",
      "profession" : "clerk",
      "id": 3
   }
}

根据这些信息,我们将提供以下RESTful API。

Sr.No. URI HTTP方法 POST身体 结果
1listUsersGETempty 显示所有用户的列表。
2addUserPOST JSON字符串 添加新用户的详细信息。
3deleteUserDELETE JSON字符串 Delete an existing user.
4:idGETempty 显示用户的详细信息。

假设您已经知道如何使用Ajax或简单的表单数据从前端传递值以及如何使用快速Request对象处理它们,我将以硬编码的形式保留所有示例的大部分内容。

列出用户

让我们在server.js文件中使用以下代码实现我们的第一个RESTful API listUsers -

server.js

var express = require('express');
var app = express();
var fs = require("fs");
app.get('/listUsers', function (req, res) {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
      console.log( data );
      res.end( data );
   });
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

现在尝试使用URL: http://127.0.0.1:8081/listUsers访问已定义的API URL: http://127.0.0.1:8081/listUsersHTTP Method : GET使用任何REST客户端在本地计算机上进行HTTP Method : GET 。 这应该产生以下结果 -

将解决方案放入生产环境时,可以更改给定的IP地址。

{
   "user1" : {
      "name" : "mahesh",
      "password" : "password1",
      "profession" : "teacher",
      "id": 1
   },
   "user2" : {
      "name" : "suresh",
      "password" : "password2",
      "profession" : "librarian",
      "id": 2
   },
   "user3" : {
      "name" : "ramesh",
      "password" : "password3",
      "profession" : "clerk",
      "id": 3
   }
}

添加用户

以下API将向您展示如何在列表中添加新用户。 以下是新用户的详细信息 -

user = {
   "user4" : {
      "name" : "mohit",
      "password" : "password4",
      "profession" : "teacher",
      "id": 4
   }
}

你可以使用Ajax调用以JSON的形式接受相同的输入,但是从教学的角度来看,我们在这里进行硬编码。 以下是数据库中新用户的addUser API -

server.js

var express = require('express');
var app = express();
var fs = require("fs");
var user = {
   "user4" : {
      "name" : "mohit",
      "password" : "password4",
      "profession" : "teacher",
      "id": 4
   }
}
app.post('/addUser', function (req, res) {
   // First read existing users.
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
      data = JSON.parse( data );
      data["user4"] = user["user4"];
      console.log( data );
      res.end( JSON.stringify(data));
   });
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

现在尝试使用URL: http://127.0.0.1:8081/addUser访问已定义的API URL: http://127.0.0.1:8081/addUserHTTP Method : POST使用任何REST客户端在本地计算机上HTTP Method : POST 。 这应该产生以下结果 -

{
   "user1":{"name":"mahesh","password":"password1","profession":"teacher","id":1},
   "user2":{"name":"suresh","password":"password2","profession":"librarian","id":2},
   "user3":{"name":"ramesh","password":"password3","profession":"clerk","id":3},
   "user4":{"name":"mohit","password":"password4","profession":"teacher","id":4}
}

查看详细

现在我们将实现一个将使用用户ID调用的API,它将显示相应用户的详细信息。

server.js

var express = require('express');
var app = express();
var fs = require("fs");
app.get('/:id', function (req, res) {
   // First read existing users.
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
      var users = JSON.parse( data );
      var user = users["user" + req.params.id] 
      console.log( user );
      res.end( JSON.stringify(user));
   });
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

现在尝试使用URL: http://127.0.0.1:8081/2访问已定义的API URL: http://127.0.0.1:8081/2HTTP Method : GET使用任何REST客户端在本地计算机上进行HTTP Method : GET 。 这应该产生以下结果 -

{"name":"suresh","password":"password2","profession":"librarian","id":2}

删除用户

此API与addUser API非常相似,我们通过req.body接收输入数据,然后根据用户ID从数据库中删除该用户。 为了简化我们的程序,我们假设我们要删除ID为2的用户。

server.js

var express = require('express');
var app = express();
var fs = require("fs");
var id = 2;
app.delete('/deleteUser', function (req, res) {
   // First read existing users.
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
      data = JSON.parse( data );
      delete data["user" + 2];
      console.log( data );
      res.end( JSON.stringify(data));
   });
})
var server = app.listen(8081, function () {
   var host = server.address().address
   var port = server.address().port
   console.log("Example app listening at http://%s:%s", host, port)
})

现在尝试使用URL: http://127.0.0.1:8081/deleteUser访问已定义的API URL: http://127.0.0.1:8081/deleteUserHTTP Method : DELETE使用任何REST客户端在本地计算机上进行HTTP Method : DELETE 。 这应该产生以下结果 -

{"user1":{"name":"mahesh","password":"password1","profession":"teacher","id":1},
"user3":{"name":"ramesh","password":"password3","profession":"clerk","id":3}}

Node.js - Scaling Application

Node.js以单线程模式运行,但它使用事件驱动的范例来处理并发。 它还有助于创建子进程,以便在基于多核CPU的系统上利用并行处理。

子进程总是有三个流child.stdinchild.stdoutchild.stderr ,它们可以与父进程的stdio流共享。

Node提供了child_process模块,该模块具有以下三种创建子进程的主要方法。

  • exec - child_process.exec方法在shell /控制台中运行命令并缓冲输出。

  • spawn - child_process.spawn使用给定命令启动新进程。

  • fork - child_process.fork方法是spawn()创建子进程的特例。

The exec() method

child_process.exec方法在shell中运行命令并缓冲输出。 它有以下签名 -

child_process.exec(command[, options], callback)

参数 (Parameters)

以下是所用参数的说明 -

  • command (String)要使用以空格分隔的参数运行的命令

  • options (Object)可能包含以下一个或多个选项 -

    • cwd (String)子进程的当前工作目录

    • env (Object)环境键值对

    • encoding (String)(默认值:'utf8')

    • shell (String)用于执行命令的Shell(UNIX上的默认:'/ bin/sh',Windows上的'cmd.exe',shell应该理解UNIX上的-c开关或Windows上的/ s/c。在Windows上,命令行解析应该与cmd.exe兼容。)

    • timeout (数字)(默认值:0)

    • maxBuffer (Number)(默认值:200 * 1024)

    • killSignal (String)(默认值:'SIGTERM')

    • uid (Number)设置进程的用户标识。

    • gid (Number)设置进程的组标识。

  • callback该函数获取三个参数errorstdout,stderr ,它们在进程终止时使用输出调用。

exec()方法返回一个具有最大大小的缓冲区,并等待进程结束并尝试一次返回所有缓冲的数据。

例子 (Example)

让我们创建两个名为support.js和master.js的js文件 -

File: support.js

console.log("Child Process " + process.argv[2] + " executed." );

File: master.js

const fs = require('fs');
const child_process = require('child_process');
for(var i=0; i<3; i++) {
   var workerProcess = child_process.exec('node support.js '+i,function 
      (error, stdout, stderr) {
      if (error) {
         console.log(error.stack);
         console.log('Error code: '+error.code);
         console.log('Signal received: '+error.signal);
      }
      console.log('stdout: ' + stdout);
      console.log('stderr: ' + stderr);
   });
   workerProcess.on('exit', function (code) {
      console.log('Child process exited with exit code '+code);
   });
}

现在运行master.js来查看结果 -

$ node master.js

验证输出。 服务器已启动。

Child process exited with exit code 0
stdout: Child Process 1 executed.
stderr:
Child process exited with exit code 0
stdout: Child Process 0 executed.
stderr:
Child process exited with exit code 0
stdout: Child Process 2 executed.

The spawn() Method

child_process.spawn方法使用给定命令启动新进程。 它有以下签名 -

child_process.spawn(command[, args][, options])

参数 (Parameters)

以下是所用参数的说明 -

  • command (String)要运行的命令

  • args (Array)字符串参数列表

  • options (Object)可能包含以下一个或多个选项 -

    • cwd (String)子进程的当前工作目录。

    • env (Object)环境键值对。

    • stdio (Array)String Child的stdio配置。

    • customFds (Array)已弃用的子文件描述符,用于stdio。

    • detached (布尔值)子将成为进程组的领导者。

    • uid (Number)设置进程的用户标识。

    • gid (Number)设置进程的组标识。

spawn()方法返回流(stdout和stderr),当进程返回大量数据时应该使用它。 一旦进程开始执行,spawn()就开始接收响应。

例子 (Example)

创建两个名为support.js和master.js的js文件 -

File: support.js

console.log("Child Process " + process.argv[2] + " executed." );

File: master.js

const fs = require('fs');
const child_process = require('child_process');
for(var i = 0; i<3; i++) {
   var workerProcess = child_process.spawn('node', ['support.js', i]);
   workerProcess.stdout.on('data', function (data) {
      console.log('stdout: ' + data);
   });
   workerProcess.stderr.on('data', function (data) {
      console.log('stderr: ' + data);
   });
   workerProcess.on('close', function (code) {
      console.log('child process exited with code ' + code);
   });
}

现在运行master.js来查看结果 -

$ node master.js

验证输出。 服务器已启动

stdout: Child Process 0 executed.
child process exited with code 0
stdout: Child Process 1 executed.
stdout: Child Process 2 executed.
child process exited with code 0
child process exited with code 0

The fork() Method

child_process.fork方法是spawn()创建Node进程的特例。 它有以下签名 -

child_process.fork(modulePath[, args][, options])

参数 (Parameters)

以下是所用参数的说明 -

  • modulePath (String)要在子级中运行的模块。

  • args (Array)字符串参数列表

  • options (Object)可能包含以下一个或多个选项 -

    • cwd (String)子进程的当前工作目录。

    • env (Object)环境键值对。

    • execPath (String)用于创建子进程的可执行文件。

    • execArgv (Array)传递给可执行文件的字符串参数列表(默认值:process.execArgv)。

    • silent (布尔值)如果为true,则子节点的stdin,stdout和stderr将通过管道输送到父节点,否则它们将从父节点继承,请参阅spawn()的stdio的“管道”和“继承”选项更多细节(默认为false)。

    • uid (Number)设置进程的用户标识。

    • gid (Number)设置进程的组标识。

除了在普通的ChildProcess实例中具有所有方法之外,fork方法还返回具有内置通信通道的对象。

例子 (Example)

创建两个名为support.js和master.js的js文件 -

File: support.js

console.log("Child Process " + process.argv[2] + " executed." );

File: master.js

const fs = require('fs');
const child_process = require('child_process');
for(var i=0; i<3; i++) {
   var worker_process = child_process.fork("support.js", [i]);	
   worker_process.on('close', function (code) {
      console.log('child process exited with code ' + code);
   });
}

现在运行master.js来查看结果 -

$ node master.js

验证输出。 服务器已启动。

Child Process 0 executed.
Child Process 1 executed.
Child Process 2 executed.
child process exited with code 0
child process exited with code 0
child process exited with code 0

Node.js - Packaging

JXcore,是一个开源项目,它引入了一个独特的功能,用于将源文件和其他资产打包和加密到JX包中。

假设您有一个包含许多文件的大型项目。 JXcore可以将它们全部打包到一个文件中以简化分发。 本章简要概述了从安装JXcore开始的整个过程。

JXcore安装

安装JXcore非常简单。 在这里,我们提供了有关如何在系统上安装JXcore的逐步说明。 按照下面给出的步骤 -

Step 1

根据您的操作系统和机器架构,从https://github.com/jxcore/jxcore下载JXcore软件包。 我们下载了一个在64位计算机上运行的Cenots软件包。

$ wget https://s3.amazonaws.com/nodejx/jx_rh64.zip

Step 2

解压缩下载的文件jx_rh64.zip并将jx二进制文件复制到/ usr/bin中,或者根据系统设置将其放在任何其他目录中。

$ unzip jx_rh64.zip
$ cp jx_rh64/jx /usr/bin

Step 3

适当地设置PATH变量以从任何你喜欢的地方运行jx。

$ export PATH=$PATH:/usr/bin

Step 4

您可以通过发出如下所示的简单命令来验证安装。 您应该发现它正常工作并打印其版本号如下 -

$ jx --version
v0.10.32

打包代码

假设您有一个包含以下目录的项目,其中保存了所有文件,包括Node.js,主文件,index.js以及本地安装的所有模块。

drwxr-xr-x  2 root root  4096 Nov 13 12:42 images
-rwxr-xr-x  1 root root 30457 Mar  6 12:19 index.htm
-rwxr-xr-x  1 root root 30452 Mar  1 12:54 index.js
drwxr-xr-x 23 root root  4096 Jan 15 03:48 node_modules
drwxr-xr-x  2 root root  4096 Mar 21 06:10 scripts
drwxr-xr-x  2 root root  4096 Feb 15 11:56 style

要打包上面的项目,您只需要进入此目录并发出以下jx命令。 假设index.js是Node.js项目的入口文件 -

$ jx package index.js index

在这里,您可以使用任何其他包名称而不是index. 我们使用了index因为我们希望将主文件名保存为index.jx。 但是,上面的命令将打包所有内容并将创建以下两个文件 -

  • index.jxp这是一个中间文件,包含编译项目所需的完整项目详细信息。

  • index.jx这是具有完整包的二进制文件,可以将其发送到您的客户端或生产环境。

启动JX文件

考虑一下你原来的Node.js项目运行如下 -

$ node index.js command_line_arguments

使用JXcore编译包后,可以按如下方式启动它 -

$ jx index.jx command_line_arguments

要了解有关JXcore的更多信息,您可以查看其官方网站。

↑回到顶部↑
WIKI教程 @2018