NodeJS入门

参考文献:https://www.tutorialspoint.com/nodejs/nodejs_quick_guide.htm

introduction

Node.js是一个基于V8引擎的服务端平台。简单来说

Node.js = Runtime Environment + JavaScript Library

Node.js应用程序由以下三个重要组件组成:

  • 导入所需模块
  • 创建服务器
  • 读取请求和响应请求

创建Node.js应用程序

step 1. 导入所需模块
我们使用require命令加载所需模块并返回模块实例到局部变量中,如下所示:

var http = require("http");				//导入Node.js Build-in模块
var square = require("./hello.js");		//导入自定义js文件,所有hello.js文件内容都会被执行。

附录:Node.js Build-in Modules and functions
参考:https://www.w3schools.com/nodejs/ref_modules.asp

ModuleDescription
assert提供一系列的断言测试功能
buffer处理二进制数据
child_process运行子进程
cluster将当前进程克隆成多个同时运行的子进程
cryptoOpenSSL加密函数
dgram提供UDP数据报套接字的实现
dns域名查询服务
events处理事件
fs文件系统模块
http将Node.Js设为http服务器
https将Node.js设为https服务器
path处理文件路径
net创建服务器和客户端
os提供操作系统的信息
querystring将请求参数字符串转为一个object对象
readline将数据流中数据以行的形式读出
stream处理数据流
string_decoder将Buffer对象解码为字符串
timers在指定时间后执行一个命令
tls提供了实现传输层(TLS Transport Layer Security)和安全套接层(SSL Secure Socket Layer)的方法
url实现url对象和字符串之间的转换
util一些实用的函数
zlib用于压缩和解压文件
vm在虚拟机中编译JavaScript代码

step 2. 创建服务器
通过http.createServer()创建http服务器,然后通过listen将服务器绑定到8081端口。

var http = require('http');

http.createServer(function(request, response){
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end('Hello World!\n');
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

step 3. 测试请求和响应
将第二步代码保存为main.js,然后进入该文件目录,运行node命令:

node main.js

验证输出为:

Server running at http://127.0.0.1:8081/

打开浏览器输入http://127.0.0.1:8081/
在这里插入图片描述

NPM

Node包管理器(Node Package Manager)主要有两个作用:

  • 在线查询node.js包的仓库(search.nodejs.org)
  • 提供安装node.js包的命令行工具,以及包的版本管理和依赖管理

npm随Node.js绑定安装。如果需要把npm升级到最新版本,通过如下命令进行:

npm install npm -g

其中-g表示global全局。
安装任何Node.js模块的命令如下:

npm install <Module Name>

比如安装大名鼎鼎的web框架模块express

npm install express

安装好后,express就会出现在工程目录下的node_modules目录中。
查看安装信息:

npm list

在这里插入图片描述
现在就可以通过require语句导入express模块:

var express = require('express');

卸载一个模块:

npm uninstall express

更新一个模块:

npm update express

回调的概念

回调函数是指当满足某种条件后用函数指针的形式调用函数。在Node.js中,所有API都支持回调的方式编写。当异步执行API函数时,不会等待API函数执行完,而是继续下个语句,当API函数执行完后再以回调的方式返回函数执行结果。比如fs模块下异步读取文件的API函数readFile的阻塞形式为readFileSync。
现创建一个名为input.txt的文本文件,内容如下:

Tutorials Point 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");

运行结果:

Tutorials Point is giving self learning content
to teach the world in simple and easy way!!!!!
Program Ended
非阻塞代码示例:
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");

运行结果:

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

结论:阻塞程序按顺序执行,异步程序按回调的方式执行

在Node.js中,任何异步函数都接受回调函数作为最后一个参数,而回调函数接受错误作为第一个参数。

事件

事件和回调不同之处在于,回调函数是在异步函数执行完成之后执行的,事件是在事件触发之后执行的。事件采用观察者模式,事件监听函数充当Observer,观察者会不断循环检测事件是否被触发。

  1. 创建事件发射器
    var events = require('events');					//导入事件模块
    var eventEmitter = new events.EventEmitter();	//创建事件发射器
    
  2. 注册事件
    eventEmitter.on('eventName', eventHandler);
    
  3. 触发事件
    eventEmitter.emit('eventName');
    

举例:

var events = require('events');
var eventEmitter = new events.EventEmitter();

var connectHandler = function connected(){
    console.log('connnected successful.');
    eventEmitter.emit('data_received');
};

eventEmitter.on('connection', connectHandler);
eventEmitter.on('data_received', function(){
    console.log('data received successfully.');
});

eventEmitter.emit('connection');
console.log('Program Ended.');

注:

  1. 同一个事件可以添加多个监听器,事件触发后会执行所有监听器,执行顺序按照添加时的列表顺序执行。
    var events = require('events');
    var eventEmitter = new events.EventEmitter();
    
    var eventHandler1 = function(){
    	console.log('event 1');
    }
    var eventHandler2 = function(){
    	console.log('event 2');
    }
    var eventHandler3 = function(){
    	console.log('event 3');
    }
    
    eventEmitter.addListener('event', eventHandler1);
    eventEmitter.on('event', eventHandler2);//on完全等价于addListener
    eventEmitter.on('event', eventHandler3);
    
    eventEmitter.emit('event');
    
    输出:
    event 1
    event 2
    event 3
    
    1. EventEmitter方法列表
No.MethodDescription
1addListener(event, listener)为事件注册监听器
2on(event, listener)为事件注册监听器
3once(event, listener)只添加一次性的监听器,执行一次后就被删除
4removeListener(event, listener)移除事件的某个监听器
5removeAllListeners([event])移除事件的所有监听器
6setMaxListeners(n)默认情况下,事件添加10个监听器就会给出警告,通过该函数可以调整监听器的数量,当为0时表示可以添加无限个监听器
7listeners(event)返回某事件的监听器列表
8emit(event, [arg1], [arg2], … \dots )触发事件
9listenerCount(emitter, event)返回某事件的监听器数量

http模块

本节参考:
[1]. https://nodejs.org/api/http.html
[2]. https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

HTTP(Hypertext Transfer Protocol, 超文本传输协议)是基于请求和响应模式、无状态的应用层协议。
Http请求由三部分组成,分别是:请求行、消息报头、请求正文。

  1. 请求行
    请求行格式:Method Request-URI HTTP-Version CRLF
    中间以空格隔开。其中Method表示请求方法;Request-URI是统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行。
    请求方法列表:
MethodDescription
GET请求Request-URI所标识的资源
POST在Request-URI所标识的资源后附加新的数据
HEAD请求由Request-URI所标识的资源的响应消息头
PUT请求服务器存储一个资源,并用Request-URI作为其标识
DELETE请求服务器删除Request-URI所标识的资源
  1. 消息报头
    HTTP消息由客户端到服务端请求和服务端到客户端响应组成。具体包括普通报头、请求报头、响应报头、实体报头。
    (1). 请求报头允许客户端向服务端传递请求的附加信息以及客户端自身的信息。
    常用的请求报头包括:
NameDescription
Accept用于指定客户端接受哪些类型的信息。比如Accept: image/gif,表示客户端希望接受GIF图像格式的资源;Accept: text/html,表示客户端希望接受html文本。
Accept-Charset用于指定客户端接受的字符集。比如Accept-Charset:iso-8859-1,gb2312,缺省值是任何字符都接受
Accept-Encoding用于指定客户端可接受的内容编码。比如Accept-Encoding:gzip,deflate。大流量的站点都采用gzip压缩技术将网页内容压缩,以提高访问速度,是指WWW服务器中安装的功能。
Accept-Language用于指定客户端的语言,如Accept-Language: zh-cn
Authorization用于证明客户端有权查看某个资源,当收到服务器的响应代码为401(未授权),可以发送Authorization请求,要求服务器对其进行验证。比如Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l,具体请参考:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Authorization
Host(必需)用于指定被请求资源的主机和端口号,通常从HTTP-URL中提取出来,比如:我们在浏览器中输入:http://www.guet.edu.cn/index.html,就会包含Host请求报头域,如下:Host: www.guet.edu.cn,此处使用了缺省端口号80
User-Agent允许客户端将操作系统、浏览器和其他属性告诉服务器。

请求报头举例:

GET /form.html HTTP/1.1 (CRLF)
Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/* (CRLF)
Accept-Language:zh-cn (CRLF)
Accept-Encoding:gzip,deflate (CRLF)
If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)
If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
Host:www.guet.edu.cn (CRLF)
Connection:Keep-Alive (CRLF)
(CRLF)

(2). 响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息。

NameDescription
Location用于重定向接受者到一个新的位置。常用于响应在更换域名的时候。
Server包含了服务器信息,比如Server: Apache-Coyote/1.1
WWW-Authenticate该报头域必须包含在401(未授权)响应消息中,比如WWW-Authentivate

(3). 实体报头

NameDescription
Content-Encoding表示被应用到实体正文内容的编码信息,比如服务器采用了gzip压缩方法,则Content-Encoding: gzip
Content-Length指定实体正文的长度,以字节的形式存储
Content-Type指明发送给接收者的实体正文的媒体类型,比如Conten-Type:text/html;charset=ISO-8859-1
Last-Modified指定资源最后修改日期和时间
Expires用于指定浏览器缓存页面的最后有效时间,超过这段时间浏览器就无法使用缓存页面,比如Expires:Thu,15 Sep 2006 16:23:12 GMT,为了让浏览器不要缓存页面,可将Expires设为o

Web模块

web服务器时用于处理HTTP请求的软件应用程序,通常会返回一些带图片、样式表和脚本代码的html文档。
web应用的架构通常分为四层:
在这里插入图片描述

  1. 创建web服务器
    创建一个server.js文件,内容如下:
    var http = require('http');
    var fs = require('fs');
    var url = require('url');
    
    http.createServer(function(request, response){
    	var pathname = url.parse(request.url).pathname;
    	console.log("Request for "+pathname+" received");
    	const filename = pathname.substring(1);
    	fs.readFile(filename, function(err, data){
        	if(err){
            	console.log(err);
            	response.writeHead(404, {'Content-Type': 'text/html'});
        	}else{
            	response.writeHead(200, {'Content-Type': 'text/html'});
            	response.write(data.toString());
        	}
    	});
    }).listen(8081);
    
    console.log('Server running at http://127.0.0.1:8081');
    
    创建index.html
    <html>
    <head>
      	<title>Sample Page</title>
    </head>
    
    <body>
      	Hello World!
    </body>
    </html>
    
    运行server
    node server.js
    
    在这里插入图片描述

Express框架

本节参考:
https://expressjs.com/en/starter/installing.html

Express框架的核心功能:

  • 允许设置中间件来响应HTTP请求
  • 定义路由表,根据HTTP方法和URL来执行不同的操作
  • 允许将参数传递给模板来动态呈现HTML页面

Hello world

const express = require('express');
const app = express();
const port = 8081;

app.get('/', (request, response)=>{
	response.send('Hello World!');
});

app.listen(port, function(){
	console.log('App listening at port ${port}');
});
node main.js

路由

1. 路由格式:
路由是确定服务器如何响应客户端请求的特定端点。路由的定义如下:

app.METHOD(PATH, HADLE)

其中:

  • app是express的实例
  • METHOD是HTTP请求方法,小写。比如get,post,put,delete,也可以使用app.all()处理所有HTTP方法,并使用app.use()将中间件指定为回调函数
  • PATH是服务器上的路径
  • HANDLER是路由匹配时的回调函数

同一个端点可以有多个回调函数,但是要添加next参数,使用next()将控制权转交给下一个回调函数。

var express = require('express');
var app = express();

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

function callback1(request, response, next){
    console.log('Get request 1');
    next();
};

function callback2(request, response, next){
    console.log('Get request 2');
    response.end();
};

app.get('/', [callback1, callback2]);

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});
Get request 1
Get request 2

Route参数
用于捕捉URL中特定位置的参数值,捕捉的参数值被放到request.params中。比如:

app.get('/user/:name/:age', (request, response)=>{
    response.send(request.params);
});

在这里插入图片描述
express.Router模块化路由
所谓模块化就是将路由封装起来,以中间件的形式使用,避免主程序代码过多冗余,从而不利于代码阅读。
首先创建一个route.js文件

const express = require('express');
const router = express.Router();

router.use(function(request, response, next){
    console.log('Time: ', Date.now());
    next();
});

router.get('/', function(request, response){
    response.send('API Home Page');
});

router.get('/about', function(request, response){
    response.send('API About Page');
});

module.exports = router;

然后在主程序中以中间件的形式使用它

var express = require('express');
var app = express();
const api = require('./route');

app.use('/api', api);

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});

现在,/api就表示该路由的主端点:
在这里插入图片描述
在这里插入图片描述

response返回方法:
response对象用于向客户端发送响应,如果路由回调函数没有发送以下方法作为响应,客户端的请求将会一直挂起。

MethodDescription
res.download()提示客户端下载文件
res.end()结束response响应,如果没有参数,则不回传任何数据结束响应
res.json()响应一个json数据
res.redirect([status, ]path)以指定的status请求重定向到指定path下,status缺省值为302"Found"
res.render(view)渲染一个view,并返回渲染好的html文档,view是个view模板的路径字符串参数
res.send([body])向客户端发送数据,参数可以是Buffer对象、字符串、object、boolean、array
res.sendFile(path [,options][, fn])向客户端发送文件,文件类型由response的HTTP头域Content-Type指定,如下例所示。
res.sendStatus()设置response的状态并以字符形式向客户端发送
var express = require('express');
var app = express();

app.get('/', (request, response)=>{
    //response.set('Content-Type', 'text/html');
    const path = __dirname+"/success.html";
    var options = {
        headers: {
            'Content-Type': 'text/html'
        }
    };
    response.status(404).sendFile(path, options, function(err){
        if(err)
            next(err);
        else
            console.log('Send:', path);
    });
});

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});

Response设置HTTP头方法

NameDescription
res.set()设置response的HTTP头
res.status(code)设置response的HTTP状态
res.type()设置Content-Type内容格式
res.append()添加特定的头域内容到HTTP头中,如果HTTP头不存在则先创建。注:如果使用append后再使用set会覆盖
res.cookie(k, v[, options])设置客户端的cookie键值对,options请查看链接中的表格
res.clearCookie(k[, options])清除k所对应的cookie

Stream是一个对象,该对象主要功能是:
(1). 读取内容
(2). 写入内容
在Node.js中有四种类型的流,分别是:

  • Readable - 用于读取数据的Stream
  • Writable - 用于写入数据的Stream
  • Duplex - 用于读写数据的Stream
  • Transform - 用于处理读入的数据,并给出相应的输出

每个Stream都是一个事件观察者EventEmitter,它们注册的事件包括:

  • data - 当Stream中有可读取的数据时触发该事件
  • end - 当Stream中没有可读取的数据时触发该事件
  • error - Stream中出现错误时触发该事件
  • finish - 当Stream中所有数据都flush到系统中触发

1. 利用Stream读取数据
创建input.txt文件,内容如下:

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

main.js内容:

var express = require('express');
const path = require('path');
var fs = require('fs');
var app = express();

var data = '';
var readerStream = fs.createReadStream(path.join(__dirname, './input.txt'));
readerStream.setEncoding('UTF-8');
readerStream.on('data', function(chunk){
    data += chunk;
});
readerStream.on('end', function(){
    console.log(data);
});
readerStream.on('error', function(err){
    console.log(err.stack);
});

app.get('/', function(request, response, next){
    response.write(data, "utf-8", function(err){
        if(err)
            next(err)
        else
            console.log('Write data finished.\n');
    });
    response.end();
});

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});

2. 利用Stream写入数据

var express = require('express');
const path = require('path');
var fs = require('fs');
var app = express();

var data = 'Hello World!';

var writerStream = fs.createWriteStream('output.txt');
writerStream.write(data, 'utf-8');
writerStream.end();

writerStream.on('finish', function(){
    console.log("Write Complete.");
});

writerStream.on('error', function(err){
    console.log(err.stack);
});

app.get('/', function(request, response, next){
    response.end();
});

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});

3. 管道机制
管道是将一个Stream的输出作为另一个Stream的输入。比如:

var express = require('express');
const path = require('path');
var fs = require('fs');
var app = express();

var data = 'Hello World!';
var readerStream = fs.createReadStream(path.join(__dirname, "/input.txt"));
var writerStream = fs.createWriteStream('output.txt');
readerStream.pipe(writerStream);

writerStream.on('finish', function(){
    console.log("Write Complete.");
});

writerStream.on('error', function(err){
    console.log(err.stack);
});

app.get('/', function(request, response, next){
    response.end();
});

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});

压缩input.txt

var express = require('express');
const path = require('path');
var fs = require('fs');
var app = express();
var zlib = require('zlib');

fs.createReadStream(path.join(__dirname, '/input.txt')).pipe(zlib.createGzip()).pipe(fs.createWriteStream('input.txt.gz'));

app.get('/', function(request, response, next){
    response.end();
});

var server = app.listen(8081, function(){
    var host = '127.0.0.1';
    var port = server.address().port;

    console.log("Server Running at http://%s:%s", host, port);
});

解压缩

// Decompress the file input.txt.gz to input.txt
fs.createReadStream('input.txt.gz')
   .pipe(zlib.createGunzip())
   .pipe(fs.createWriteStream('input.txt'));

Child Process模块

本节参考:
https://nodejs.org/docs/latest-v15.x/api/child_process.html

子进程模块用于创建子进程。每个子进程自带三个流对象:child.stdin、child.stdout、和child.stderr。在node.js中。

1.异步创建子进程

有四种方式异步创建子进程:spawn()、fork()、exec()、execFile()。

NameDescription
spawn(command[, args][, options])使用command创建新进程
fork(modulePath[, args][, options])是spawn的特殊形式,如fork(’./son.js’)相当于spawn(‘node’, [’./son.js’])。而且fork会在父进程和子进程之间建立通信管道,用于进程之间的通信
exec(command[, options], callback)生成一个shell,然后command在该shell中运行,子进程执行完毕后将结果存放在回调函数的参数中。
execFile(file[, args][, options][, callback])功能类似于exec,但不生成shell
2. 同步创建子进程
NameDescription
object spawnSync(command[, args][, options])等价于spawn,但是只有子进程退出才返回
string execSync(command[, options])等价于exec,但是只有子进程退出才返回
string execFileSync(command[, args][, options])等价于execFile,但是只有子进程退出才返回
3. 事件
NameDescription
close子进程的stdio流被关闭时触发
exit子进程结束时触发,由于多个子进程可以共享流,所以进程结束时,其流并没有被关闭。
disconnect在执行disconnect()方法时触发
message子进程使用process.send()时触发
spawn子进程spawn成功时触发,如果spawn不成功则触发error
error1. 该进程无法spawn 2. 该进程无法被killed 3. 向子进程发送消息失败 触发
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Node.js是一种基于Chrome V8引擎的JavaScript运行时环境,通常用于构建高度可扩展的网络应用程序。相比传统的使用JavaScript运行在浏览器中的开发,Node.js允许我们在服务器端运行JavaScript代码,使得服务器端和客户端的开发能够使用相同的编程语言,提供了更高效的开发方式。 对于想要入门Node.js的开发者来说,了解Node.js的基本概念和特性非常重要。有很多优秀的教程和资源可供学习,其中包括一些免费的PDF书籍。 Node.js入门PDF可以帮助初学者以更系统化的方式学习和理解Node.js的基本知识和技能。这些PDF通常包含以下内容: 1. Node.js的基本介绍:包括Node.js的背景和起源、其特性和优势等。 2. Node.js的安装和配置:包括在不同操作系统上安装Node.js的步骤和设置,使得开发者可以在自己的电脑上运行Node.js环境。 3. Node.js的基本语法和特性:包括如何编写和运行Node.js代码,如何使用模块和包管理工具等。 4. Node.js的核心模块和API:介绍Node.js提供的核心模块和API,如文件系统、网络、HTTP等,帮助开发者理解如何使用这些模块来构建应用程序。 5. 异步编程和事件驱动:介绍Node.js的异步编程模型和事件驱动机制,帮助开发者编写高效和响应式的应用程序。 虽然Node.js入门PDF可以作为入门学习的起点,但实际上要掌握Node.js的开发还需要不断实践和深入学习。最好结合阅读PDF教程和参与实际项目来提升自己的技能。同时,社区中也有很多开发者分享自己的经验和教程,可以通过阅读博客、参加技术交流活动等方式来进一步提升自己的Node.js技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值