一、Nod.js基本概念
1.为什么学Node
-
企业需求:具有服务端开发需求
-
目的:打开服务端黑匣子
-
网站开发能力:服务端,前端,运维部署
2.Node是什么?
-
Node.js不是语言,不是库,也不是框架
-
是JS运行时环境(是一个平台),可以解析和执行JS代码
3. Node.js 中的 JavaScript
- 没有 BOM、DOM
- EcmaScript 基本的 JavaScript 语言部分
- 在 Node 中为 JavaScript 提供了一些服务器级别的 API
- 文件操作的能力
- http 服务的能力
- 网络服务构建的能力
- EcmaScript
- 变量
- 方法
- 数据类型
- 内置对象
- Array
- Object
- Date
- Math
二、基本Node操作
1.使用Node执行js脚本文件
注意:node文件名不要用node.js命名,不要使用中文
例1
var foo = 'hello nodejs'
console.log(foo)
在终端或者cmd里中node + 文件名便可执行文件
(我这个文件的名字叫做Hello_wrold.js)
可以看出,node和js基本语法一样
例2
console.log(window)
console.log(document)
我们在node中执行js的一些操作,结果如下:
没有任何输出,但是我们在html中打开浏览器界面,引用这个js文件在控制台可以看见
注意:Node和浏览器中的 JavaScript 不一样
2.Node的读文件基本操作
注意:
1.
浏览器中的 JavaScript 是没有文件操作的能力的,但是 Node 中的 JavaScript 具有文件操作的能力
2.
在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块; 在 fs 这个核心模块中,就提供了所有的文件操作相关的 API
3.
fs 是 file-system 的简写,就是文件系统的意思;例如:fs.readFile 就是用来读取文件的
a.使用 require 方法加载 fs 核心模块
var fs = require('fs')
b.读取文件
注意:
1.
第一个参数就是要读取的文件路径
2.
第二个参数是一个回调函数
3.
回调函数又有两个参数:error和data;如果读取路径成功,data返回数据,error返回null;反之,如果读取路径失败,data返回null,error返回错误对象
fs.readFile('./data/hello.txt', function (error, data) {
console.log(data)
})
(我创建了一个名为data的文件夹,里面保存了一个名为hello.txt的文件,内容为:hello node)
结果如下:
注意:
文件中存储的其实都是二进制数据 0 1; 这里为什么看到的不是 0 和 1 呢?原因是二进制转为 16 进制了;但是无论是二进制01还是16进制,人类都不认识;所以我们可以通过 toString 方法把其转为我们能认识的字符
var fs = require('fs')
fs.readFile('./data/hello.txt', function (error, data) {
//console.log(data)
console.log(data.toString()) //hello node
})
在这里存在一个小问题:
如果我们将路径写错了,看看上面写的代码会出现什么问题。
var fs = require('fs')
fs.readFile('./data/a.txt', function (error, data) {
console.log(data)
})
因为data里面是null,所以结果为undefined
在这里就可以通过判断 error 来确认是否有错误发生
var fs = require('fs')
fs.readFile('./data/a.txt', function (error, data) {
//console.log(data)
//console.log(data.toString())
if (error) {
console.log('读取文件失败了')
} else {
console.log(data.toString())
}
})
如果读取失败,结果如下图所示:
3.Node的写文件基本操作
a.写文件的第一步也是使用require加载fs核心模块
var fs = require('fs')
b.写入文件
fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
console.log('文件写入成功')
})
结果会在控制台输出:文件写入成功
同时在data文件下新建你好.md文件,并把内容写入
注意:writeFile有三个参数
1.
第一个参数:文件路径
2.
第二个参数:文件内容
3.
第三个参数:回调函数。回调函数在这里只有一个参数error;若文件写入成功,error 是 null;若文件写入失败,error 就是错误对象
注意:
在这里存在一个小问题:
如果我们将路径写错了,看看上面写的代码会出现什么问题。
fs.writeFile('./d/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
console.log('文件写入成功')
})
我把data文件夹改成了d文件夹
结果如下:
只是在控制台输出语句,但是在data文件夹里没有新建文件,也没有新建d文件夹。
因此,我们可以在这里加上 if 语句进行判断
fs.writeFile('./data/你好.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
if (error) {
console.log('写入失败')
} else {
console.log('写入成功了')
}
})
三、Node之http服务
1.简单的http服务
我们可以使用 Node 非常轻松的构建一个 Web 服务器;在 Node 中专门提供了一个核心模块:http;http 这个模块的职责就是帮你创建编写服务器的
a.加载 http 核心模块
var http = require('http')
b.使用 http.createServer() 方法创建一个 Web 服务器;返回一个 Server 实例
var server = http.createServer()
c.注册 request 请求事件
当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
server.on('request', function () {
console.log('收到客户端的请求了')
})
d.绑定端口号,启动服务器
server.listen(3000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
运行该JS文件后,就可以打开浏览器
端口号范围:0~65536
2.发送响应
request 请求事件处理函数,需要接收两个参数:
- Request 请求对象
- 请求对象可以用来获取客户端的一些请求信息,例如请求路径
- Response 响应对象
- 响应对象可以用来给客户端发送响应消息
- response 对象有一个方法:write 可以用来给客户端发送响应数据
- write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
var http = require('http')
var server = http.createServer()
server.on('request', function (request, response) {
console.log('收到客户端的请求了,请求路径是:' + request.url)
response.write('hello')
response.write(' nodejs')
response.end()
})
server.listen(3000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
结果在浏览器输出:
3.练习:根据不同的请求路径返回不同数据
注意:
上面使用的 res.write方式比较麻烦,推荐使用更简单的方式,直接 end 的同时发送响应数据
// res.write('hello')
// res.write(' world')
// res.end()
res.end('hello nodejs')
练习分析:根据不同的请求路径发送不同的响应结果
-
1. 获取请求路径
+
req.url 获取到的是端口号之后的那一部分路径
·+
url:同一资源定位符,一个url其实是要定一个资源
+
也就是说所有的 url 都是以 / 开头的
-
2. 判断路径处理响应
+
响应内容只能是二进制数据或者字符串、数字、对象、数组、布尔值
var http = require('http')
var server = http.createServer()
server.on('request', function (req, res) {
console.log('收到请求了,请求路径是:' + req.url)
console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)
var url = req.url
if (url === '/') {
res.end('index page')
} else if (url === '/login') {
res.end('login page')
} else {
res.end('404 Not Found.')
}
})
server.listen(3000, function () {
console.log('服务器启动成功,可以访问了。。。')
})
4.端口号
ip 地址定位计算机
端口号定位具体的应用程序
所有需要联网通信的应用程序都会占用一个端口号
在cmd中输入
ipconfig
可以查看本机的端口号
在同一局域网的计算机可以访问自己的计算机
req.socket.remoteAddress:当前请求我的计算机客户端的地址(ip地址和端口号)
req.socket.remotePort:当前请求我的计算机客户端的端口号
根据下列代码可以看见访问自己计算机的ip地址和端口号
var http = require('http')
var server = http.createServer()
server.on('request', function (req, res) {
console.log('收到请求了,请求路径是:' + req.url)
console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort)
res.end('hello nodejs')
})
server.listen(5000, function () {
console.log('服务器启动成功,可以访问了。。。')
})
5.Content-Type
- 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
- 不同的资源对应的 Content-Type 是不一样,具体参照:http://tool.oschina.net/commons
- 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
a.在浏览器中输出汉字
在之前的学习中,如果我们在res.end中写入中文的话,打开浏览器会出现乱码的情况;
其实在服务端默认发送的数据,其实是 utf8 编码的内容;但是浏览器不知道你是 utf8 编码的内容;浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析;中文操作系统默认是 gbk
解决办法: 就是正确的告诉浏览器我给你发送的内容是什么编码的;在 http 协议中,Content-Type 就是用来告知对方我给你发送的数据内容是什么类型
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
再输出res.end语句结果就正确了
text/plain 就是普通文本
b.在浏览器中输出html标签
如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end('hello html 点我
')
结果会在浏览器中渲染成html标签
利用文件的方法,将html文件渲染成页面
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)
}
})
c.在浏览器中输出图片
-
发送的并不是文件,本质上来讲发送是文件的内容
-
当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理;图片不需要指定编码;一般只为字符数据才指定编码
fs.readFile('./resource/ab2.jpg', function (err, data) {
if (err) {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('文件读取失败,请稍后重试!')
} else {
res.setHeader('Content-Type', 'image/jpeg')
res.end(data)
}
})
四、Node中的js-模块系统
在 Node 中没有全局作用域的概念;在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
1.Node.js中的核心模块
- 核心模块是由 Node 提供的一个个的具名的模块,它们都有自己特殊的名称标识,例如
- fs 文件操作模块
- http 网络服务构建模块
- os 操作系统信息模块
- path 路径处理模块 - 所有核心模块在使用的时候都必须手动的先使用
require
方法来加载,然后才可以使用,例如:var fs = require('fs')
// 用来获取机器信息的
var os = require('os')
// 用来操作路径的
var path = require('path')
// 获取当前机器的 CPU 信息
console.log(os.cpus())
// memory 内存
console.log(os.totalmem())
// 获取一个路径中的扩展名部分
// extname extension name
console.log(path.extname('c:/a/b/c/d/hello.txt'))
2.Node.js中的模块系统
- 在 Node 中没有全局作用域的概念
- 在 Node 中,只能通过 require 方法来加载执行多个 JavaScript 脚本文件
- require 加载只能是执行其中的代码,文件与文件之间由于是模块作用域,所以不会有污染的问题
- 模块完全是封闭的
- 外部无法访问内部
- 内部也无法访问外部
- 模块作用域固然带来了一些好处,可以加载执行多个文件,可以完全避免变量命名冲突污染的问题
- 但是某些情况下,模块与模块是需要进行通信的
- 在每个模块中,都提供了一个对象:
exports
- 该对象默认是一个空对象
- 你要做的就是把需要被外部访问使用的成员手动的挂载到
exports
接口对象中 - 然后谁来
require
这个模块,谁就可以得到模块内部的exports
接口对象 - 还有其它的一些规则,具体后面讲,以及如何在项目中去使用这种编程方式,会通过后面的案例来处理