目录
- 1. Node.js简介
- 2. 模块化开发
- 2.1 为什么需要模块化开发
- 2.2 Node.js模块化开发规范
- 3. Node.js系统模块
- 3.1 文件操作系统模块(fs)
- 3.2 路径操作系统模块(path)
- 4. 第三方模块
- 4.1 获取第三方模块
- 4.2 第三方模块 nodemon
- 4.3 第三方模块 nrm
- 4.4 第三方模块 gulp
- 5. 配置文件
- 5.1 package.json配置文件
- 5.2 package-lock.json配置文件
- 6. Node.js的模块加载机制
- 6.1 有完整路径
- 6.2 没有完整路径
- 7. 创建web服务器
- 8. HTTP协议
- 9. HTTP请求与响应处理
- 9.1 参数传递
- 9.2 静态资源、动态资源
1. Node.js简介
Node是一个基于Chrome V8引擎的JavaScript代码运行环境。它是由ECMAScript及Node环境提供的一些附加API组成的,包括文件、网络、路径等等一些更加强大的API。
2. 模块化开发
2.1 为什么需要模块化开发
在传统的开发模式中,面临两个主要的问题:命名冲突和文件依赖。
我们可以通过模块化开发来解决上述问题:
概念:模块化是指把单独的一个功能封装在一个模块(文件)中,模块之间相互隔离,可以通过特定的接口开放内部成员,也可以依赖别的模块。
优点:模块化开发方便了代码的重用,从而提升了开发效率,并且便于后期的维护。
2.2 Node.js模块化开发规范
Node.js规定一个JavaScrip文件就是一个模块, 模块内部定义的变量和函数默认情况下在外部无法得到。Node.js的模块化开发有两种方式:
- 模块内部可以使用
exports
对象进行成员导出,使用require
方法导入其他模块。
//example.js
var user = {name:zhangsan,age:18}
var add = (a,b) => a+b;
exports.user = user;
exports.add = add;
// example1.js
var a = require('example.js')
console.log(a.add(10,10)) // 结果:20
console.log(a.user.name) // 结果:zhangsan
console.log(a.user.age) // 结果:18
- 使用
module.exports
进行导出
exports
是module.exports
的别名(地址引用关系),两者指向同一个对象,导出对象想用。但是,当两者导出的对象不用时,导出对象最终以module.exports
为准,exports
导出不会生效。
//example.js
var user = {name:zhangsan,age:18}
var add = (a,b) => a+b;
module.exports.user = user;
exports.add = add;
// example1.js
var a = require('example.js')
console.log(a) // 结果:{name:zhangsan,age:18} , add不会被导入
3. Node.js系统模块
Node环境提供的API就是系统模块。因为这些API都是以模块化开发的方式进行的,所以我们称Node运行环境提供的API为系统模块。
3.1 文件操作系统模块(fs)
(1)引入模块:
const fs = require('fs')
(2)读取文件内容:
fs.readFile('文件路径/文件名称','文件编码',callback)
- 第一个参数是文件路径
- 第二个参数是文件编码(可选)
- 第三个参数是回回调函数,当文件内容读取完成之后,调用这个回调函数,调用过程中,通过参数的形式将文件读取结果传递给回调函数。
fs.readFile('./base.css','utf-8', (err,doc) => {
if(!err){
console.log(doc)
}
})
Node.js的回调函数时错误优先的回调函数,回调函数的第一个参数是错误信息。如果读取成功,err为null,如果读取失败,err是一个对象。
(3)写入文件内容
fs.writeFile('文件路径/文件名称','数据',callback)
第一、三个参数和上面一样,第二个参数是需要写入的数据,是字符串类型。
当写入的文件不存在时,会自动创建文件。
3.2 路径操作系统模块(path)
由于不同操作系统的路径分隔符不同,所以要进行路径的拼接操作。
使用系统模块path,它会判断现在使用的操作系统的类型,然后使用操作系统对应的路径分隔符进行路径拼接。
(1)导入模块
const path = require('path')
(2)路径拼接
path.join('路径','路径'...)
// 示例
path.join('a','b', 'c.js') // 结果为:a/b/c.js
(3)相对路径、绝对路径
- 通常使用的是的绝对路径,因为有时候相对路径相对的是命令行工具的当前的工作目录。
- 在读取文件或者设置文件路径时都会选择绝对路径
- require方法的路径相对的是当前文件,所以可以写相对路径
- 可以使用
__dirname
(双下划线)获取当前文件的绝对路径
fs.readFile(path.join(__dirname,'base.css'),'utf-8', (err,doc) => {
if(!err){
console.log(doc)
}
})
4. 第三方模块
已经写好的、具备特定功能、可以直接使用的模块就是第三方模块。由于第三方模块通常有多个文件组成且放在一起,所以又成为“包”。
第三方模块有两种存在形式:
- 以js文件形式存在,提供实现项目具体功能的API接口
- 以命令行工具形式存在,辅助项目的开发
4.1 获取第三方模块
npmjs.com:第三方模块的存储和分发仓库
npm是node的的第三方模块管理工具
下载: npm install 模块名称
卸载: npm uninstall 模块名称
上面的安装是本地安装,只会安装到当前的项目,一般情况下:
- 命令行工具:全局安装
- 库文件:本地安装
4.2 第三方模块 nodemon
nodemon是一个命令行工具,用来辅助项目的开发。由于在nodejs 中每次修改文件都要使用命令行工具执行文件,比较麻烦。nodemon可以监控文件的修改,修改完就可以直接自动运行。
使用步骤:
- 全局安装:
npm install nodemon -g
- 在命令行中使用nodemon命令替代node命令执行文件
node helloworld.js
// 替换为
nodemon helloworld.js
这样就会一直监听文件的修改,并自动执行。可以使用ctrl+c
来终止操作。
4.3 第三方模块 nrm
nrm:npm下载地址切换工具
由于npm默认的下载工具在国外,国内下载较慢,使用nrm可以下载其他网站的相关包。使用步骤如下:
- 全局安装:
npm install nrm -g
- 查询可用于下载地址列表:
nrm ls
- 切换npm下载地址:
nrm use 名称
4.4 第三方模块 gulp
之前写了一篇关于gulp笔记,这里就不多说了,链接:《Gulp 学习笔记》
5. 配置文件
5.1 package.json配置文件
我们在安装了各种第三方依赖,模块之后,依赖文件夹的文件会非常的杂乱,可以生成一个package.json
文件,这样在安装依赖时,就会将相关信息保存在package.json
文件中。
package.json
文件是项目的描述文件,记录了当前项目的信息,例如项目的名称、作者、描述、依赖的第三方模块等,可以使用 npm init -y
命令生成。
项目的依赖分为两种:项目依赖和开发依赖
(1)项目依赖
在项目的开发阶段和线上运营阶段都需要依赖的第三方包,称为项目依赖。
执行npm install
命令,安装需要的项目依赖。执行该命令后,它就会去package.json
文件中查找dependences
字段下面的依赖项,进行安装。
(2)开发依赖
在开发项目的过程中需要的依赖,线上运营不需要的第三方包,称为开发依赖。
使用npm install 包名 --save-dev
命令将包添加到package.json
文件的devDependencies
字段中。
我们可以根据不同的换将去安装所需要的依赖,例如在生产环境中,我们可以使用以下命令来安装相关依赖:
npm install --production
这样,就只会安装项目依赖,不会安装开发依赖。
在package.json
配置文件中有一个scripts
关键字,里面是一些命令的别名的定义。执行这些别名就相当于执行了与之对应明亮命令。
5.2 package-lock.json配置文件
上面说了package.json配置文件用来记录项目的的相关信息,那么这些项目的依赖时怎么联系到一起的呢,这就需要package-lock.json
配置文件来发挥作用了。
在生成package.json
文件的同时会生成package-lock.json
文件,该配置文件有以下作用:
- 锁定包的版本,确保再次下载时不会因为包的版本不用而产生问题
- 加快下载速度,因为该文件已经记录了项目所依赖的第三方包的树状结构和下载地址,重新安装时只需要下载即可,不需要做额外的工作
6. Node.js的模块加载机制
6.1 有完整路径
在有完整路径时模块查找的规则如下:
require('./index.js')
require('./index')
-
require
方法会根据模块路径查找模块,如果是完整的路径,直接引入模块。 - 如果模块的后缀省略,就去找同名的js文件,
- 如果找不到,就找同名的文件夹,再在这个文件夹中查找
index.js
文件 - 如果找不到,就在当前文件夹(
index
文件夹)中的package
文件中查找main选项中的入口文件 - 如果指定的入口文件不存在,或者没有指定入口文件就直接报错,没有找到模块
6.2 没有完整路径
在没有完整路径时模块查找的规则如下:
require('find')
- 把
find
作为系统模块 - 去
node_modules
文件夹中查找 - 先看有没有同名的文件夹
- 如果有就找文件夹中是否有
index.js
文件 - 如果没有
index.js
文件,就查看该文件夹中的package.js
中的main
选项确定模块入口文件 - 如果指定的入口文件不存在,或者没有指定入口文件就直接报错,没有找到模块
7. 创建web服务器
创建web服务器的步骤:
// 应用系统模块
const http = require('http')
// 创建web服务器
const web = http.createServer()
// 当客户端发送请求时
app.on('request', (req,res) =>{
// 响应
res.end('响应内容')
})
// 监听3000端口
app.listen(3000)
其中req
是客户端的请求信息,res
是服务端的响应信息。
启动服务之后,可以在本地使用:localhost:3000
访问上面定义的web服务器。
8. HTTP协议
HTTP使超文本传输协议,规定了如何从服务器向客户端传输超文本内容,它是基于客户端服务器架构工作,是客户端和服务器端请求。
在HTTP请求和响应的过程中的数据块叫做报文,它包含要传送的数据和一些附加的信息。
(1)请求报文
- 通过
req.method
来获取请求的类型,根据请求方式来响应的不同的内容(返回的请求类型是大写的,例:GET) - 通过
req.url
获取请求的地址,根据请求地址来响应不用的内容 - 通过
req.headers
获取请求报文信息 - 例如,使用
req.header['accept']
获取请求头中的Accept的内容。
(2) 响应报文
设置响应报文:
res.writeHead(状态码, 响应报文信息)
第一个参数是状态码,第二个参数是响应的报文信息,它是一个对象,可以指定响应数据类型等参数。
9. HTTP请求与响应处理
9.1 参数传递
(1)GET请求
在Node.js中提供了一个url模块,专门用来处理url地址。
const url = require('url')
可以使用url.pause()
来解析url地址,他有两个参数,第一个参数是要解析的URL地址,第二个参数是一个布尔值,表示是否把查询参数解析成对象的形式,默认为false
。
在使用GET方法传参时,可以通过url.pause(req.url,true).query
来获取到解析出的请求参数对象。
(2)POST方法
POST方法的参数被放在请求体中传输,传递参数是通过事件的方式接收的:
-
data
事件:当请求参数传递的时候触发 -
end
事件:当参数传递完成之后触发
这两个事件绑定在req
上,由于post请求的参数可能不是一次性传递完成的,所以需要把参数拼接起来:
let postParams = ''
// params是传递来的参数,这里要将他们拼接起来
req.on('data', (params) => {
postParams += params
})
req.on('end', () => {
console.log(postParams)
})
req.end('ok')
在Node.js 中提供了querystring
系统模块,用来处理请求的参数。
const querystring = require('querystring')
// 将参数从字符串转化为对象
querystring.pause(postParams)
9.2 静态资源、动态资源
静态资源: 服务器不需要做处理,可以直接响应为客户端的资源就是静态资源。
动态资源: 相同的请求地址不同的响应资源,这种资源就是动态资源。
根据用户访问的路径,来在服务器查找对应的资源:
const http = require('http')
const url = require('url')
const path = require('path')
const app = http.createServer()
app.on('request', (req, res) => {
// 获取用户的请求路径
let pathname = url.pause(req.url).pathname
// 将用户的请求路径转换为服务器实际路径
let readPath = path.join(__dirname, 'public'+pathname)
// 读取文件,并返回
fs.readFile(realPath, (error, result) => {
if(error){
return
}
res.end(result)
})
})
有一点需要注意,在浏览器中全局对象是window,在Node中全局对象是global。global全局对象中也有以下方法,可以在任何地方使用,global可以省略:
- console.log()
- setTimeout()
- clearTimeout()
- setInterval()
- clearInterval()