node.js 学习笔记(一) 基础知识
文章目录
一、Node.js是什么
Node.js 不是一门语言,不是库不是框架, 是一个 JavaScript 运行时的环境,可以解析和执行 JavaScript 代码,以前只有浏览器可以解析执行JavaScript代码,现在的 JavaScript 可以脱离浏览器来执行。构建于 Chrome V8 引擎之上
node中的 JavaScript:
- 没有BOM、DOM
- ES语法
- 在 node 这个 JavaScript 执行环境中为 JavaScript 提供了一些服务器级别的操作API,如:
- 文件读写
- 网络服务的构建
- 网络通信
- http服务器
node.js 使用事件驱动(event-driven)、非阻塞IO模型(异步)(non-blocking I/O model)来达到轻量和高效的效果。npm 是世界上最大的开源库生态系统
二、Node.js 的应用
- Web 服务后台
- 命令行工具
- npm(node开发)
- git
- hexo(node开发)
三、使用node.js
3.1 使用 node.js 执行 js 脚本
步骤:
- 正常的编写 js 脚本文件
- 在脚本文件的根目录下打开 cmd,输入
node + 文件名
注意:文件名不要使用 node.js 命名
例子:
var mes = 'hello world!'
console.log(mes);
3.2 使用 node.js 读写文件
浏览器中的 JavaScript 是没有文件操作能力的,但 Node 中的 JavaScript 具有文件读写能力。在 Node 中如果想要进行文件操作,那么就要引入 fs 这个核心模块,其提供了所有文件操作相关的API。
3.2.1 读取文件
读取文件:fs.readFile()
, 其有两个参数,第一个参数是要读取的文件路径,第二个参数是回调函数:
- error:
- 若读取失败,error就是错误对象
- 若读取成功,error就为null
- data:
- 若读取失败,data 就是 undefined
- 若读取成功,data 就是读取的数据
// fs 是 file-system 的意思 文件系统
// 1. 使用require方法加载fs核心模块
let fs = require('fs');
// 2. 读取文件
fs.readFile('./hello.txt',function (error, data) {
if(error) {
console.log('读取文件失败');
} else {
console.log(data);
}
})
注意:文件中存储的其实是二进制数据,但这里看到的却不是0 和 1,是因为二进制转为了16 进制,可以通过toString()方法转换为我们认识的字符
// 1. 使用require方法加载fs核心模块
let fs = require('fs');
// 2. 读取文件
fs.readFile('./hello.txt',function (error, data) {
if(error) {
console.log('读取文件失败');
} else {
console.log(data.toString());
}
})
3.2.2 写文件
写文件:fs. writeFile()
,有三个参数:文件路径、文件内容和回调函数(只有error一个形参)
fs.writeFile('./hello.txt', '大家好呀!!', function (error) {
if (error) {
console.log('写入失败')
} else {
console.log('写入成功');
}
});
3.3 使用 node.js 提供 http 服务
可以使用 node 轻松的构建一个 web 服务器,node 中提供的核心模块:http,辅助创建服务器
步骤:
- 加载 http 核心模块
- 使用
http.createServer()
方法创建一个 web 服务器,返回一个 Server 实例 - 服务器接收请求,接收到请求后自动触发 request 请求事件,执行回调函数对请求进行处理,并发送响应
- 绑定端口号,启动服务器,监听是否有请求
要点:
- 一个请求对应一个响应,如果在一个请求的过程中,已经结束响应了,则不能重复发送响应
- 没有请求就没有响应
基本格式:
//1. 加载http核心模块
let http = require('http');
//2. 使用http.createServer()方法创建一个web服务器
let server = http.createServer();
//3. 服务器接收请求,接收到请求后自动触发request请求事件,执行回调函数
server.on('request',function(req,res) {
...
})
//4. 绑定端口号,启动服务器
server.listen(3000,function() {
...
});
简写格式:
let http = require('http');
http
.createServer(function (req, res) {
...
})
.listen(3000, function () {
...
})
3.3.1 request 请求事件
request请求事件处理函数接收两个参数:
- Request 请求对象:用来获取客户端的一些请求信息,例如请求路径
- Response 响应对象:用来给客户端发送响应信息。有一个方法:**write()**用来给客户端发送响应信息,write 可以使用多次,但是最后一次一定要使用 end 来结束响应,一次性把所有响应内容呈现给客户端,否则客户端会一直等待。
3.3.2 案例
案例1:
//1. 加载http核心模块
let http = require('http');
//2. 使用http.createServer()方法创建一个web服务器
let server = http.createServer();
//3. 服务器接收请求,接收到请求后自动触发request请求事件,执行回调函数
server.on('request',function(req,res) {
console.log('收到客户端请求');
})
//4. 绑定端口号,启动服务器
server.listen(3000,function() {
console.log("服务器启动成功,可通过 http://127.0.0.1:3000/ 来访问");
});
访问 http://127.0.0.1:3000/ 后 命令行界面:
案例2:
在案例1的基础上进一步添加请求处理和发送响应的功能:
//1. 加载http核心模块
let http = require('http');
//2. 使用http.createServer()方法创建一个web服务器
let server = http.createServer();
//3. 服务器接收请求,接收到请求后自动触发request请求事件,执行回调函数
server.on('request',function(request,response) {
console.log('收到客户端请求, 请求路径是:' + request.url);
//response
response.write('hello');
response.write(' node.js');
response.end();
})
//4. 绑定端口号,启动服务器
server.listen(3000,function() {
console.log("服务器启动成功,可通过 http://127.0.0.1:3000/ 来访问");
});
服务器端:
客户端:
注意:
-
修改代码后,需要重启node才会生效
-
以上的代码针对不同的路径都响应同样的内容,而实际开发中一定是不同的请求响应不同的内容
三、Node中的 JS 模块
3.1 模块系统
要点:
-
在 node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
-
require 就是一个方法,有两个作用:
- 用来加载执行模块的代码
- 拿到被加载文件模块导出的接口对象
-
自定义模块中require方法中的相对路径必须加 ./,不能省略否则会报错,因为去掉./后node就会把该模块当成核心模块
-
在 node 中,没有全局作用域,只有模块作用域,外部访问不到内部,内部也访问不到外部
3.2 核心模块
Node 为 JavaScript 提供了很多服务器级别的 API,这些API绝大多数都被包装到一个具名的核心模块中了。例如文件操作的 fs
模块,http 服务构建的 http
模块…
想要使用核心模块,必须要用 require 引入,如:
const fs = require('fs');
3.3 用户自定义模块
案例:简单的自定义模块化
// 这是 a.js 文件
var foo = 'aaa';
console.log('a start');
require('./b.js'); // ./不能省略
console.log('a end');
console.log(foo)
// 这是 b.js 文件
var foo = 'bbb';
console.log('bbbbb');
执行a.js 后,结果为:
a start
bbbbb
a end
aaa //没有全局作用域,不同模块中后面同名变量的值不会覆盖当前模块中同名变量的值
在 node 中,没有全局作用域,只有模块作用域,外部访问不到内部,内部也访问不到外部。但我们时常希望访问其他模块中的成员和方法,怎么解决呢???
解决方案见3.4
3.4 模块的加载与导出
在每个文件模块中都提供了一个对象:exports,默认是一个空对象,把所有需要被外部访问的成员都挂载到 exports 对象中
案例:
// 这是 a.js 文件
// 得到 b 的exports 对象,不是其中的某一个成员或方法
let bExports = require('./b.js');
console.log(bExports.foo); // hello
console.log(bExports.add(10,30)) //40
// 这是 b.js 文件
var foo = 'hello';
//左边的foo是exports中的成员键值,右边的foo是b.js模块中的变量
exports.foo = foo;
exports.add = function(x,y) {
return x + y;
}
function add(x,y) {
return x - y;
}
四、IP地址和端口号
- IP 地址用来定位计算机
- 端口号用来定位具体的应用程序(进程)
- 一切需要联网通信的软件都会占用一个端口号
- 端口号范围从0~65536 之间
- 可以同时开启多个服务,但一定要确保不同服务占用的端口号不一致才可以
4.1 相应响应类型Content-Type
在服务器端默认发送的数据其实是 utf-8 编码的内容,但浏览器并不知道是utf-8编码的内容,就会按照当前操作系统的默认编码(gbk)去解析,解决方法:告诉浏览器服务器发送的内容是什么编码形式的,使用 content-Type 来告知浏览器发送的数据是什么类型
let http = require('http');
let server = http.createServer();
server.on('request',function(req,resp) {
res.setHeader('Content-Type','text/plain;charset=utf-8');
res.end('hello 世界');
})
server.listen(3000,function() {
console.log("服务器启动成功!");
});
4.2 通过网络发送文件
let http = require('http');
let fs = require('fs');
let server = http.createServer();
server.on('request',function(req,resp) {
fs.readFile('./resource/index.html',function(err,data) {
if(err) {
res.setHeader('Content-Type','text/plain;charset=utf-8');
res.end('文件读取失败,请稍后重试!')
} else {
res.setHeader('Content-Type','text/html;charset=utf-8');
res.end(data);
}
})
})
server.listen(3000,function() {
console.log("服务器启动成功!");
});
要点:
- 若 res.end() 中的字符串里满足 html 标签格式,虽然返回的是字符串,但浏览器会将其作为标签来解析。加上res.setHeader(‘Content-Type’,‘text/plain;charset=utf-8’);后就会当成普通文本来处理
- 查询不同资源对应的 content-type 的网址:http://tool.oschina.net/