Fork me on GitHub
余鸢

node.js入门

Hello World HTTP server

首先,为您的平台安装Node.js。

在这个例子中,我们将创建一个监听端口1337的HTTP服务器,它发送Hello,World! 到浏览器。 请注意,您可以使用任何其他服务当前未使用的端口号,而不使用端口1337。

http模块是一个Node.js 核心模块(Node.js源代码中包含的一个模块,不需要安装额外的资源)。 http模块提供使用http.createServer()方法创建HTTP服务器的功能。 要创建应用程序,请创建一个包含以下JavaScript代码的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const http = require('http'); // Loads the http module
http.createServer((request, response) => {
// 1. Tell the browser everything is OK (Status code 200), and the data is in plain text
response.writeHead(200, {
'Content-Type': 'text/plain'
});
// 2. Write the announced text to the body of the page
response.write('Hello, World!\n');
// 3. Tell the server that all of the response headers and body have been sent
response.end();
}).listen(1337); // 4. Tells the server what port to be on

使用任何文件名保存文件。 在这种情况下,如果我们将其命名为hello.js,则可以通过转到文件所在的目录并使用以下命令来运行应用程序:

1
node hello.js

然后可以使用浏览器中的URL http://localhost:1337http://127.0.0.1:1337访问创建的服务器。

一个简单的网页会在顶部显示一个“Hello,World!”文本,如下面的截图所示。

sp170514_214939

Hello World命令行

Node.js也可以用来创建命令行实用程序。 下面的代码从命令行参数读取一个字符串以打印一个Hello消息。

要运行这段代码:

  1. 创建一个空文件,并粘贴下面的代码。 该文件的名称不重要,但很多人会将此文件命名为app.js或main.js.
  2. 更改文件的权限,使其成为可执行文件。 示例chmod 700 FILE_NAME
  3. 通过键入./APP_NAME运行应用程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/env node
'use strict';
/*
The process.argv property returns an array containing the command line
arguments passed when the Node.js process was launched. The first element
will be process.execPath. The second element will be the path to the
JavaScript file being executed. The remaining elements will be any
additional command line arguments.
Example: [ 'node', '/path/to/yourscript', 'arg1', 'arg2', ... ]
URL: https://nodejs.org/api/process.html#process_process_argv
*/
// 1. Extract the name of the app/file name.
var appName = process.argv[1].split('/').pop();
// 2. Save the first provided argument as the username.
var name = process.argv[2];
// 3. Check if the name was provided.
if (!name) {
// 1. Give the user an example how to use the app.
console.log(`Missing argument! \n\n\tExample: ${appName} YOUR_NAME\n`);
// -> Exit the app if error. The nr 1 tells the system that the app quit
// with an error, thus another command won't be executed. For example:
// ./hello && ls -> won't execute ls
// ./hello David && ls -> will execute ls
process.exit(1);
}
// 4. Display the message in the console.
console.log(`Hello, ${name}!`);

Hello World with Express

以下示例使用Express创建一个监听端口3000的HTTP服务器,响应“Hello,World!”。

首先,创建一个新的文件夹,例如。对myApp。 进入myApp并制作一个包含以下代码的新的JavaScript文件(例如,我们将其命名为hello.js)。 然后从命令行使用“npm install –save express”安装快速模块。 请参阅本文档了解如何安装软件包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Import the top-level function of express
var express = require('express');
// Creates an Express application using the top-level function
var app = express();
// Define port number as 3000
const port = 3000;
// Routes HTTP GET requests to the specified path "/" with the specified callback function
app.get('/', function(request, response) {
response.send('Hello, World!');
});
// Make the app listen on port 3000
app.listen(port, function() {
console.log('Server listening on http://localhost:' + port);
});

从命令行,运行以下命令:

1
node hello.js

打开浏览器并浏览 http://localhost:3000http://127.0.0.1:3000查看响应。

安装并运行Node.js

安装

首先,在您的开发计算机上安装Node.js。

Windows:转到 Node.js下载站点并下载/运行安装程序。

Mac:转到 Node.js下载站点并下载/运行安装程序。 或者,您可以通过brew install node安装节点。 Homebrew允许您通过命令行管理包。 您可以在Homebrew 网站上阅读更多信息。

Linux:按照命令行安装页面上的发行说明进行操作。

运行节点程序

要运行Node.js程序,只需运行节点app.jsnodejs app.js,其中app.js是节点应用程序源代码的文件名。

或者,节点程序可以作为脚本执行。 为此,需要从指向节点解释器的shebang开始,例如 #!/usr/bin/env node。 然后,该文件必须设置为可执行文件。 现在脚本可以直接从命令行运行。

Hello World基本路由

一旦您了解如何使用节点创建HTTP 服务器,了解如何使其根据用户导航的路径“做”事情很重要。 这种现象称为“路由”。

最基本的例子是检查 if (request.url === 'some/path/here'),然后调用一个响应一个新文件的函数。

这里可以看到一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var http = require('http');
function index (request, response) {
response.writeHead(200);
response.end('Hello, World!');
}
http.createServer(function (request, response) {
if (request.url === '/') {
return index(request, response);
}
response.writeHead(404);
response.end(http.STATUS_CODES[404]);
}).listen(1337);

如果你继续定义这样的“路由”,那么你最终会得到一个大量的回调函数,我们不想像这样的大混乱,所以我们来看看我们是否可以清理它。

首先,我们将所有路由存储在一个对象中:

1
2
3
4
5
6
7
8
9
10
var routes = {
'/': function index (request, response) {
response.writeHead(200);
response.end('Hello, World!');
},
'/foo': function foo (request, response) {
response.writeHead(200);
response.end('You are now viewing "foo"');
}
}

现在我们已经在一个对象中存储了2条路由,现在我们可以在我们的主要回调中检查它们:

1
2
3
4
5
6
7
8
9
10
http.createServer(function (request, response) {
if (request.url in routes) {
return routes[request.url](request, response);
}
response.writeHead(404);
response.end(http.STATUS_CODES[404]);
}).listen(1337);

现在每次尝试浏览您的网站时,它将检查您的路线中是否存在该路径,它将调用相应的功能。 如果没有找到路由,服务器将使用404(未找到)进行响应。

在那里你有它 - 使用HTTP Server API路由非常简单。

调试您的NodeJS应用程序

您可以使用节点检查器。 运行此命令通过npm进行安装:

1
npm install -g node-inspector

然后您可以使用调试您的应用程序

1
node-debug app.js

Github存储库可以在这里找到:https://github.com/node-inspector/node-inspector

调试本机

您也可以通过如下启动来本机调试node.js:

1
node debug your-script.js

要在您想要的代码行中完全断开调试器,请使用以下命令:

1
debugger;

Hello World in the REPL

当没有参数调用时,Node.js启动也称为“Node shell”的REPL(Read-Eval-Print-Loop)。

在命令提示符下键入节点。

1
2
$ node
>

在Node shell提示符>下输入“Hello World!”

1
2
3
$ node
> "Hello World!"
'Hello World!'

在线部署您的应用程序

将应用程序部署到特定于(Node.js)的托管环境时,此环境通常提供可用于运行服务器的PORT环境变量。 将端口号更改为process.env.PORT允许您访问应用程序。

例如,

1
2
3
http.createServer(function(request, response) {
// your server code
}).listen(process.env.PORT);

另外,如果要在调试时离线访问,可以使用:

1
2
3
http.createServer(function(request, response) {
// your server code
}).listen(process.env.PORT || 3000);

其中3000是离线端口号。

Core modules

Node.js是一个Javascript引擎(Google的Chrome V8引擎,用C ++编写),允许在浏览器之外运行Javascript。 虽然许多库可用于扩展Node的功能,但引擎配备了一组实现基本功能的核心模块。

节点目前包含34个核心模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[ 'assert',
'buffer',
'c/c++_addons',
'child_process',
'cluster',
'console',
'crypto',
'deprecated_apis',
'dns',
'domain',
'Events',
'fs',
'http',
'https',
'module',
'net',
'os',
'path',
'punycode',
'querystring',
'readline',
'repl',
'stream',
'string_decoder',
'timers',
'tls_(ssl)',
'tracing',
'tty',
'dgram',
'url',
'util',
'v8',
'vm',
'zlib' ]

此列表是从Node文档API https://nodejs.org/api/all.html(JSON文件:https://nodejs.org/api/all.json)获得的。

所有核心模块一目了然

assert

assert 模块提供了一组简单的断言测试,可用于测试不变量。

buffer

在ECMAScript 2015(ES6)引入TypedArray之前,JavaScript语言没有读取或操纵二进制数据流的机制。 Buffer类作为Node.js API的一部分引入,可以在TCP流和文件系统操作等上下文中与八位字节流进行交互。

现在,在ES6中添加了 TypedArrayBuffer类实现了Uint8Array API以更优化的方式适用于Node.js的用例。

c/c++_addons

Node.js Addons是使用C或C ++编写的动态链接共享对象,可以使用require()函数加载到Node.js中,并且就像它们是普通的Node.js模块一样使用。 它们主要用于在Node.js和C / C ++库之间运行的JavaScript之间提供接口。

child_process

child_process模块提供了以与popen(3)相似但不完全相同的方式生成子进程的功能。

cluster

Node.js的单个实例在单个线程中运行。 为了利用多核系统,用户有时会想要启动一个Node.js进程的集群来处理负载。 集群模块允许您轻松创建所有共享服务器端口的子进程。

console

console 模块提供了一个简单的调试控制台,类似于Web浏览器提供的JavaScript控制台机制。

crypto(加密)

crypto模块提供加密功能,其包括用于OpenSSL的哈希,HMAC,加密,解密,签名和验证功能的一组包装器。

deprecated_apis

当以下情况之一时,Node.js可能会弃用API:(a)API的使用被认为是不安全的,(b)改进的替代API已经可用,或者(c)在将来的主要版本中预期会发生对API的更改。

DNS

dns模块包含属于两个不同类别的功能:

  1. 使用底层操作系统设施执行名称解析的功能,并且不一定执行任何网络通信。 此类别只包含一个函数:dns.lookup()
  2. 连接到实际DNS服务器以执行名称解析的功能,并且始终使用网络执行DNS查询。 此类别包含除dns.lookup()之外的dns模块中的所有功能。

domain(域)

此模块正在等待弃用。一旦替换API已经完成,该模块将被完全弃用。大多数终端用户不应该使用这个模块。绝对必须具有域名功能的用户可能依赖于它,但应该期望在将来迁移到不同的解决方案。

Events

Node.js的核心API大部分是围绕一个惯用的异步事件驱动架构构建的,其中某些类型的对象(称为“发射器”)周期性地发出命名的事件,这些事件会引起Function对象(“监听器”)的调用。

FS

文件I / O由标准POSIX功能的简单包装器提供。要使用这个模块请require('fs')。所有的方法都有异步和同步的形式。

http

Node.js中的HTTP接口旨在支持传统上很难使用的协议的许多功能。特别地,大的,可能的块编码的消息。界面注意不要缓冲整个请求或响应 - 用户能够流式传输数据。

HTTPS

HTTPS是TLS / SSL上的HTTP协议。 在Node.js中,这是作为单独的模块实现的。

module

Node.js有一个简单的模块加载系统。 在Node.js中,文件和模块是一一对应的(每个文件被视为单独的模块)。

net

net模块为您提供了一个异步网络包装器。 它包含用于创建服务器和客户端(称为流)的功能。 您可以将此模块与require('net');包含在一起。

os

os模块提供了许多与操作系统相关的实用方法。

path

路径模块提供用于处理文件和目录路径的实用程序。

punycode

Node.js中捆绑的punycode模块的版本已被弃用。

querystring

querystring模块提供用于解析和格式化URL查询字符串的实用程序。

readline

readline模块提供一个从Readable流读取数据的接口(如process.stdin),一行一行。

repl

repl模块提供Read-Eval-Print-Loop(REPL)实现,该实现既可以作为独立程序使用,也可以包含在其他应用程序中。

stream

Stream是用于在Node.js中处理流数据的抽象界面。 流模块提供了一个基本API,可以轻松构建实现流接口的对象。

Node.js提供了许多流对象。 例如,对HTTP服务器和process.stdout的请求都是流实例。

string_decoder

string_decoder模块提供了一种API,用于将Buffer对象解码为字符串,以保留编码的多字节UTF-8和UTF-16字符。

timers

timer 模块暴露了一个全局API,用于在将来某个时间段调用的调度功能。 因为定时器功能是全局变量,所以不需要调用 require('timers')来使用API。

Node.js中的定时器功能实现与Web浏览器提供的timers API类似的API,但使用围绕 Node.js事件循环构建的不同内部实现。

tls_(ssl)

tls模块提供了构建在OpenSSL之上的传输层安全(TLS)和安全套接层(SSL)协议的实现。

tracing

跟踪事件提供了一种机制,用于集中由V8,节点核心和用户空间代码生成的跟踪信息。

可以通过在启动Node.js应用程序时传递启用了--trace-events-enabled来启用跟踪。

tty

tty模块提供了tty.ReadStreamtty.WriteStream类。 在大多数情况下,直接使用本模块是没有必要或可能的。

dgram

dgram模块提供UDP数据报套接字的实现。

url

url模块提供用于URL解析和解析的实用程序。

util

util模块主要用于支持Node.js自己的内部API的需求。 然而,许多实用程序对于应用程序和模块开发人员也是有用的。

v8

v8模块公开了特定于Node.js二进制内置的V8版本的API。

注意:API和实现可随时更改。

vm

vm模块提供用于在V8虚拟机上下文中编译和运行代码的API。 JavaScript代码可以编译并立即运行或编译,保存并稍后运行。

注意:vm模块不是安全机制。 不要使用它来运行不受信任的代码。

zlib

zlib模块提供使用Gzip和Deflate / Inflate实现的压缩功能。

TLS Socket:服务器和客户端

此与常规TCP连接之间的唯一主要区别是私钥和公共证书,您必须将其设置为选项对象。

如何创建密钥和证书

此安全过程的第一步是创建私钥。这个私钥是什么?基本上,它是用于加密信息的一组随机噪声。在理论上,你可以创建一个键,并使用它来加密任何你想要的。但最好的做法是为特定的东西使用不同的键。因为如果有人偷你的私钥,就像有人偷你的钥匙一样。想象一下,如果你使用相同的钥匙来锁定你的车,车库,办公室等

openssl genrsa -out private-key.pem 1024

一旦我们有了私钥,我们就可以创建一个CSR(证书签名请求),这是我们要求私人密钥由一个花哨的权威机构签署的。这就是为什么你必须输入与贵公司有关的信息。此信息将由签名机构查看,并用于验证您。在我们的情况下,您输入的内容并不重要,因为在下一步中,我们将自己签署证书。

openssl req -new -key private-key.pem -out csr.pem

现在我们已经填写了我们的文件,现在是假装我们是一个很酷的签名机构的时候了。

openssl x509 -req -in csr.pem -signkey private-key.pem -out public-cert.pem

现在您拥有私钥和公共证书,可以建立两个NodeJS应用之间的安全连接。 而且可以在示例代码中看到,这是一个非常简单的过程。

重要!

由于我们自己创建了公开的证书,所以我们的证书是无价值的,因为我们是无私的。 NodeJS服务器默认不会信任这样的证书,这就是为什么我们需要告诉它实际上信任我们的证书,并使用以下选项rejectUnauthorized:false。 非常重要:在生产环境中,不要将此变量设置为true。

TLS Socket Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
'use strict';
var tls = require('tls');
var fs = require('fs');
const PORT = 1337;
const HOST = '127.0.0.1'
var options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('public-cert.pem')
};
var server = tls.createServer(options, function(socket) {
// Send a friendly message
socket.write("I am the server sending you a message.");
// Print the data that we received
socket.on('data', function(data) {
console.log('Received: %s [it is %d bytes long]',
data.toString().replace(/(\n)/gm,""),
data.length);
});
// Let us know when the transmission is over
socket.on('end', function() {
console.log('EOT (End Of Transmission)');
});
});
// Start listening on a specific port and address
server.listen(PORT, HOST, function() {
console.log("I'm listening at %s, on port %s", HOST, PORT);
});
// When an error occurs, show it.
server.on('error', function(error) {
console.error(error);
// Close the connection after the error occurred.
server.destroy();
});

TLS Socket Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
'use strict';
var tls = require('tls');
var fs = require('fs');
const PORT = 1337;
const HOST = '127.0.0.1'
// Pass the certs to the server and let it know to process even unauthorized certs.
var options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('public-cert.pem'),
rejectUnauthorized: false
};
var client = tls.connect(PORT, HOST, options, function() {
// Check if the authorization worked
if (client.authorized) {
console.log("Connection authorized by a Certificate Authority.");
} else {
console.log("Connection not authorized: " + client.authorizationError)
}
// Send a friendly message
client.write("I am the client sending you a message.");
});
client.on("data", function(data) {
console.log('Received: %s [it is %d bytes long]',
data.toString().replace(/(\n)/gm,""),
data.length);
// Close the connection after receiving the message
client.end();
});
client.on('close', function() {
console.log("Connection closed");
});
// When an error ocoures, show it.
client.on('error', function(error) {
console.error(error);
// Close the connection after the error occurred.
client.destroy();
});