一、 Node.js介绍
1、为什么要学 Node.js
- 企业需求
- 招聘条件:具有服务端开发经验更好
- front-end 前端
- back-end 后端
- 全栈开发工程师
- 全干
- 基本的网站开发能力
- 服务端
- 客户端
- 运维部署
- 多人社区
2. Node.js 是什么
-
Node.js® 是一个基于 Chrome V8 引擎 的 JavaScript 运行时。 (JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中。)
- Node.js 不是一门语言
- Node.js 不是库、不是框架
- Node.js 是一个 JavaScript 运行时环境
- 简单来讲:Node.js 可以解析和运行 JavaScript 代码
- 以前只有 浏览器 可以解析执行 JavaScript 代码
- 也就是说现在的 JavaScript 可以完全 脱离浏览器来运行,一切都归功于: Node.js
-
浏览器中的 JavaScript
- EcmaScript
- 基本的语法
- if
- var
- function
- object
- array
- BOM
- DOM
- EcmaScript
-
Node.js 中的 JavaScript
- 没有 BOM、DOM 服务端不处理 BOM、DOM
- 有 EcmaScript
- 在Node这个JavaScript执行环境中为JavaScript提供了一些服务器级别的操作API
- 例如文件读写
- 网络服务的构建
- 网络通信
- http服务器
- 等处理。。。
-
构建于 Chrome 的 V8 引擎之上 Node.js® 是一个基于 Chrome V8 引擎 的 JavaScript 运行时。(JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中。)
- 代码只是具有特定格式的字符串而已
- 引擎可以认识它,引擎可以帮你去解析和执行
- Google Chrome的 V8引擎 是目前公认的 解析执行 JavaScript代码最快
- Node.js 的作者把Google Chrome中的 V8引擎 移植了出来,开发了一个独立的 JavaScript运行时环境。
3. Node.js 能做什么
-
Web 服务器后台
-
命令行工具
- npm (node开发的)
- git (c语言开发的)
- hexo (node开发的)
- 。。。
-
对于前端开发工程师,接触node最多是它的命令行
-
webpack
-
gulp
-
npm
-
二、安装 Node 环境
官网下载,然后配置环境变量。
三、HelloWorld 使用 Node 执行 js脚本文件
创建js文件
console.log("Hello World");
进入js脚本文件所在目录
输入命令
node helloworld.js
终端会输出Hello World
总结:
-
使用Node执行 js脚本:
1、创建并编写JS脚本文件
2、打开终端,定位到脚本文件所属目录
3、输入node 文件名
即可执行对应的文件 -
Node中的 js具有文件操控的能力:
- 浏览器中的 JavaScript是 没有文件操作的能力
- 但是 Node 中的JavaScript 具有 文件操作的能力
fs 是 file-system 的简写
在 Node中如果想要进行文件操作,就必须引入 fs 这个核心模块
在 fs 这个核心模块中,提供了所有的文件操作相关的 API。例如: fs.readFile 是用来读取文件。
-
使用 require 方法加载 fs 核心模块
var fs = require('fs')
可以
var a = require('fs')
, 但是括号里的 fs 不能是其他的。 -
读取文件
第一个参数是 要读取的文件路径
第二个参数是 一个回调函数
读取成功:
data 读到的数据
error null
读取失败:
data null
error 错误对象fs.readFile('./data/hello.txt', function (error, data) { console.log(data) // 结果:<Buffer 38 38 39 0d 0a e6 96 87 e4 bb b6 e6 93 8d e4 bd 9c e7 9a 84 e8 83 bd e5 8a 9b> // 文件中存储的其实都是二进制数据 0 1 // 这里为什么看到的不是0和1呢?原因是二进制转为16进制了 // 但是无论是二进制还是16进制,人类都不认识 // 所以我们可以通过 toString方法把其转为我们能认识的字符 console.log(data.toString()) // 结果:889 // 文件操作的能力 })
四、写文件和简单的错误处理
1、写文件
使用 require 方法加载 fs 核心模块
var fs = require('fs')
写入文件:
第一个参数: 文件路径
第二个参数: 文件内容
第三个参数: 回调函数
- 写入成功:
文件成功写入:error 是 null - 写入失败:
文件写入失败:error 是 错误对象
fs.writeFile('./data/写文件.md', '大家好,现在是node写了几句话在文件里', function (error) {
console.log('文件写入成功')
})
2、简单的错误处理
fs.writeFile('./data/写文件.md', '大家好,现在是node写了几句话在文件里', function (error) {
if (error) {
console.log('写入失败')
} else {
console.log('写入成功')
}
})
五、简单的http服务
使用 Node 非常轻松的构建一个 Web 服务器,(也就相当于在做Apache)
在Node中专门提供了一个核心模块: http
http这个模块的职责就是帮你创建编写服务器。
1、创建 http服务器
-
加载 http 核心模块
var http = require('http')
-
使用 http.createServer() 方法创建一个 Web 服务器
返回一个 Server 实例
var server = http.createServer()
-
提供对数据的服务
注册 request 请求事件
当客户端请求过来,就会 自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数server.on('request', function () { console.log('收到客户端的请求了') })
-
绑定端口号,启动服务器。(为什么绑定端口号?因为网络通信就需要端口)
**127.0.0.1 **是回送地址,指本地机,一般用来测试使用。回送地址(127.x.x.x)是本机回送地址(Loopback Address),即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回,不进行任何网络传输。
server.listen(3000, function () { console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问') })
测试:
2、运行js文件(即启动http服务器)
开启服务器:
node 创建http服务.js
服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问
客户端发起请求:
在浏览器输入http://127.0.0.1:3000/ 后,
命令行出现:现在服务器已经收到客户端的请求了
关闭服务器:
ctrl+c 即关闭了服务器
若创建http服务的 js 代码被修改,需重启服务器才生效
3、发送响应:
注册 request 请求事件
当客户端请求过来,就会 自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
request请求事件处理函数,需要接收两个参数:
- Request 请求对象
请求对象可以用来获取客户端的一些请求信息,例如请求路径 - Response 响应对象
响应对象可以用来给客户端发送响应消息
server.on('request', function (request, response) {
console.log('收到客户端的请求了,请求路径是:' + request.url)
// response对象有一个方法: write 可以用来给客户端发送响应数据
// write 可以使用多次,但是最后一定要使用end来结束响应,否则客户端会一直等待
response.write('hello')
response.write('haha')
// 告诉客户端,我的话说完了,可以呈递给用户了
response.end()
})
此代码不管请求路径是什么如http://127.0.0.1:3000/aaa,都响应为hellohaha
注:在浏览器输入 127.0.0.1:3000 浏览器会自动 认为是 127.0.0.1:3000\
由于现在我们的服务器的能力还非常的弱,无论是什么请求,都只能响应hellohaha
我希望当请求不同的路径的时候响应不同的结果
例如:
/index
/login 登陆
/register 注册
判断 url 就可以了解决这个问题了
根据不同的请求返回不同数据
-
加载 http 核心模块
var http = require('http')
-
使用 http.createServer() 方法创建一个 Web 服务器
返回一个 Server 实例
var server = http.createServer()
-
注册 request 请求事件
当客户端请求过来,就会 自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数request请求事件处理函数,需要接收两个参数:
- Request 请求对象
请求对象可以用来获取客户端的一些请求信息,例如请求路径 - Response 响应对象
响应对象可以用来给客户端发送响应消息
server.on('request', function (req, res) { console.log('收到客户端的请求了,请求路径是:' + req.url) // res.write('hello') // res.write('haha') // res.end() // 上面的方式比较麻烦,推荐使用更简单的方式,直接end的同时发送数据 // res.end('hello haha') //根据不同的请求路径发送不同的响应结果 // 1.获取请求路径(req.url获取的是端口号后的路径,以 / 开头) // 2.判断路径处理响应 var url = req.url if (url === '/') { res.end('index page') } else if (url === '/login') { res.end('login page') } else { res.end('404 Not Found.') } })
一个简单的接口:
if (url === '/products') { var products = [ { name: '西瓜', price: 10 }, { name: '苹果', price: 56 } ] // res.end()里响应内容只能是二进制数据或字符串,所以使用JSON.stringify将该数组转换为字符串 res.end(JSON.stringify(products)) }
- Request 请求对象
-
绑定端口号,启动服务器。(为什么绑定端口号?因为网络通信就需要端口)
**127.0.0.1 **是回送地址,指本地机,一般用来测试使用。回送地址(127.x.x.x)是本机回送地址(Loopback Address),即主机IP堆栈内部的IP地址,主要用于网络软件测试以及本地机进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回,不进行任何网络传输。
server.listen(3000, function () { console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问') })
浏览器默认端口号是80,若输入127.0.0.1 就默认端口号是80
响应内容类型 Content-type
-
在服务端默认发送的数据,其实是utf8编码的内容。
但是浏览器不知道你是utf8编码的内容。 -
浏览器在不知道服务器响应内容的编码的情况下会按照当前操作系统的默认编码去解析。
-
中文操作系统默认是gbk。
-
response.end('hello 世界') // 页面出现乱码
-
解决方法 就是正确的告诉浏览器我给你发送的内容是什么编码的。
-
在http协议中,Content-Type 就是用来告知对方发送的数据内容是什么类型。
response.setHeader('Content-type', 'text/plain; charset=utf-8') response.end('hello 世界') // 没有出现乱码
-
text / html 将 html标签字符串 渲染成 html
var url = request.url if (url === '/wantplain') { response.setHeader('Content-type', 'text/plain; charset=utf-8') // text/plain 是普通文本 res.end('hello 世界') } else if (url === '/wanthtml') { // 如果发送的是html格式的字符串,要想要浏览器渲染成html,就需要加: response.setHeader('Content-type', 'text/html; charset=utf-8') // 若用 text/plain 则显示普通含html标签的字符串 // 若都不加,即不加content-type,浏览器也能将html标签字符串自动渲染成html,但若有汉字,则乱码。 response.end('<p>hello html <a href="">点我</a></p>') }
-
图片和html类型等资源读取
if (url === '/') { // 读文件 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) } }) } else if (url === '/photo') { // 读文件 fs.readFile('./resource/1.png', function (err, data) { if (err) { // 读取失败 res.setHeader('Content-type', 'text/plain; charset=utf-8') res.end('文件读取失败,请稍后重试') } else { // 读取成功 // data 默认是二进制数据,可以通过.toString 转为我们能识别的字符串 // res.end() 支持两种数据类型,一种是二进制,一种是字符串 // 图片就不需要指定编码,因为我们常说的编码一般指的是: 字符编码 res.setHeader('Content-type', 'image/png') res.end(data) } }) }
-
HTTP Content-type 对照表
网址:https://tool.oschina.net/commons
常见的:
- .css -----------> text/css
- .txt ------------> text/plain
- .png ----------> image/png
- .jpg -----------> image/jpeg
- .js -------------> application/x-javascript
-
-
var http = require('http')
var server = http.createServer()
server.on('request', function (request, response) {
// 用来告知对方我发送的数据内容是什么类型。否则出现乱码
response.setHeader('Content-type', 'text/plain; charset=utf-8')
response.end('hello 世界')
})
server.listen(3000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
六、Node 中的模块系统
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。
模块 是 Node.js 应用程序 的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是 JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
Node 中的 JavaScript
-
EcmaScript
-
核心模块
-
第三方模块
-
自定义模块
在Node 中,模块有三种 :
-
具名的核心模块,例如 fs、 http
-
第三方模块
如果传递给require(的模块标识符不是一个内置模块, 也没有以./
或../
开头, 则Node.js会从当前模块的父目录开始,尝试从/node_modules
文件夹中加载第三方模块。
如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录。 -
自定义模块
-
必须指定以
./
或../
开头的路径标识符。在加载自定义模块时,如果没有指定./
或../
这样的路径标识符,则node会把它当作内置模块或第三方模块进行加载。若不存在此模块,则报错。 -
可以省略后缀名 require(./b.js) -> require(./b)
-
在Node中,没有全局作用域,只有模块作用域
- 即 外部访问不到内部,内部也访问不到外部。
- 即 文件 访问不到其内的 模块中的代码,文件访问不到包含它的 文件
-
让模块和模块直接进行通信
-
require 方法有两个作用:
1、加载文件模块并执行里面的代码;
b.js
console.log('b被加载执行了')
a.js
console.log('a start') require('./b.js') console.log('a end')
结果是
a start b被加载执行了 a end
2、拿到被加载文件模块导出的接口对象。
在每个文件模块中都提供了一个对象 : exports。exports 默认是一个空对象。
所有需要被外部访问的成员前面都需加上 exports.
b.js
var foo = 'bbb' // 不能被外部访问 exports.foo = 'hello' // 能被外部访问
a.js
var bExports = require('./b') console.log(bExports.foo) // 输出hello
-
-
-
将目录作为模块
当把目录作为模块标识符,传递给require()
进行加载的时候,有三种加载方式:
① 在被加载的目录下查找一个叫package.json
的文件,并寻找main
属性,作为require()
加载的入口
② 如果目录里没有package.json
文件,或者main
入口不存在或无法解析,则Node.js将会试图加载目录下的index.js
文件。
③ 如果以上两步都失败,则Node.js会在终端打印错误消息,报告模块的缺失: Error: Cannot find module 'xx
ip地址 用来定位 计算机。
端口号 用来定位具体的 应用程序。
-
所有需要联网通信的应用程序 都会占用一个端口号。
-
端口号的范围 从0- 65536之间。
-
在计算机中有一些 默认端口号,最好不要去使用。
- 例如 http服务的端口号是80。
- 由于一些应用软件占用了部分端口,因此文件中的部分端口被注释掉了
-
我们在开发过程中使用一些简单好记的就可以了,例如3000、5000 等没什么含义。
-
可以同时开启多个服务,但一定要确保不同服务占用的端口号不同。
说白了,在一台计算机中,同一个端口号同一时间只能被一个程序占用。
核心模块
Node 为 JavaScript 提供了很多 服务器级别的 API, 这些 API绝大多数都被包装到了一个 具名的核心模块中。
例如: 文件操作的 fs
核心模块,http 服务构建的 http
模块,path
路径操作模块、os
操作系统信息模块 等。
引入模块:
一个核心模块,想要使用它,就必须:引入 核心模块
如 引入 文件操作的 fs
核心模块:
require 是一个方法,它的作用就是用来加载模块
var fs = require('fs')
七、初步实现 Apache
曾经学PHP使用的 Apache 服务器,此软件有默认www
目录,可以通过 localhost
或127.0.0.1:80
访问www
下的资源。
在node中,我们也可以配置资源路径,从而达到Apache 服务器的基本效果:
var http = require('http')
var server = http.createServer()
var fs = require('fs')
// 配置Apache资源路径
var wwwDir = 'D:/webnote/nodejs/www'
server.on('request', function (req, res) {
var url = req.url
var filePath = '/index.html'
if (url != '/') {
filePath = url
}
fs.readFile(wwwDir + filePath, function (err, data) {
if (err) {
return res.end('404 Not Found.')
}
res.end(data)
})
})
server.listen(5000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:5000/ 来进行访问')
})
当浏览器输入 http://127.0.0.1:5000/message.html
即可访问到www
下的message.html
了。
Node中的console(REPL)
像浏览器的控制台一样,
在终端,输入node
回车,即可。