NodeJS--01
前端框架的发展历史
学习资源推荐
- node.js官网:文档查询
- npm官网:模块搜索
- GitHub:大量的开源工具可供学习和使用
- StackOverflow:学习中遇到的问题查询
- SegmentFault:问题查询
Node.js基础
1、Node.js介绍
编译型
解释型
为什么要学习node.js?
- 辅助前端开发,搭建前端工程
- 编写服务端业务、数据库开发
什么是Node.js?
Node.js 是一个基于 Chrome V8 引擎的 JavaScript运行环境。
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
- Chrome V8
- 事件驱动
- 非阻塞I/O
Node.js 可以解析JS代码(没有浏览器安全级别的限制),提供很多系统级别的API,如fs/net/process/os等。
什么是NPM?
Node.js 的包管理器 npm,成为世界上最大的开放源代码的生态系统。
学习资源推荐
- node.js官网:文档查询
- npm官网:模块搜索
- GitHub:大量的开源工具可供学习和使用
- StackOverflow:学习中遇到的问题查询
- SegmentFault:问题查询
2、Node.js安装
版本识别:
12.3.2
- LTS 稳定版本,建议安装
- Current 最新版本
- 主版本号.子版本号.修订版本号 v6.8.x
- 子版本号为偶数的版本是稳定版本,为奇数的是非稳定版本
- 建议安装LTS的偶数版本
下载安装:
- 在官网下载.msi安装包
- 验证安装是否成功:在Git Bash中
node -v
npm -v
nvm安装
- Node Version Manager(Node版本管理工具)下载地址
- 开发工作可能会在多个Node版本中测试,Node的版本也比较多,需要一款工具来管理
- 基本命令
nvm -v
nvm list
nvm install 版本号
nvm use 版本号
Node.js内置模块
1、URL模块
url.parse('http://www.baidu.com:8080/api?user=cyr&pwd=123#100')
url.parse('http://www.baidu.com:8080/api?user=cyr&pwd=123#100', true)
// 把URL解析成对象
url.parse('://www.baidu.com:8080/api?user=cyr&pwd=123#100', true, true)
{
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.baidu.com:8080',
port: '8080',
hostname: 'www.baidu.com',
hash: '#100',
search: '?user=cyr&pwd=123',
query: 'user=cyr&pwd=123',
pathname: '/api',
path: '/api?user=cyr&pwd=123',
href: 'http://www.baidu.com:8080/api?user=cyr&pwd=123#100'
}
// 把对象格式化成URL
url.format({
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.baidu.com:8080',
port: '8080',
hostname: 'www.baidu.com',
hash: '#100',
search: '?user=cyr&pwd=123',
query: 'user=cyr&pwd=123',
pathname: '/api',
path: '/api?user=cyr&pwd=123',
})
// 把两段URL片段,组合成一个完整的URL
url.resolve('http://www.baidu.com', '/api/getList')
2、QueryString模块
- 对查询字符串执行更加强大的解析
querystring.stringify()
// 默认使用 & 进行分隔,键值用 = 连接
querystring.stringify({
name: 'qf',
course: ['nodejs', 'vue', 'react']
})
// 自定义分隔符
querystring.stringify({
name: 'qf',
course: ['nodejs', 'vue', 'react']
}, ',')
// 自定义键值对之间的分隔符
querystring.stringify({
name: 'qf',
course: ['nodejs', 'vue', 'react']
}, ',', ':')
querystring.parse() // querystring.stringify()的逆方法,也可以接受后面的两参数
querystring.escape('北京')
querystring.unescape() // 与querystring.escape互逆
3、HTTP/HTTPS 模块 - get()
目标:实现一个HTTP爬虫
需求讲解:
打开拉勾网 https://www.lagou.com
我们的目标是抓取到了一级品类和二级品类的内容
审查元素,分析其源码结构
第一步:抓取首页源码字符串
https.get(url, fn)
用于抓取页面中的静态内容和数据
第二步:使用 cheerio 进一步处理源码字符串,获取到品类名称
```
npm install cheerio -D
```
第三步:在控制台上打印出我们获取到的品类名称
var https = require('https');
var cheerio = require('cheerio');
var html = ""
https.get('https://www.lagou.com/',function(res){
res.on('data',function(str){
html+=str;
})
res.on('end',function(){
getMenu(html)
})
res.on('error',function(err){
console.log(err)
})
})
function getMenu(str){
var $ = cheerio.load(str);
var cates = [];
$('.mainNavs').find('.menu_box').each(function(index,item){
var cate = {
title:"",
list:[]
}
cate.title = $(item).find('h2').text().replace(/[\\n\s]/g,'');
$(item).find('h3').each(function(index,item){
cate.list.push($(item).text())
})
cates.push(cate)
})
console.log(cates)
}
4、HTTP/HTTPS 模块 - request()
目标:获取cnode开放数据
https.request()
cnode的api接口文档:https://cnodejs.org/api
GET 的请求方式
demo:从cnode开放平台获取文章列表
POST 的请求方式
demo:执行cnode开放平台上的文件收藏功能
var https = require('https')
var options = {
hostname: 'cnodejs.org',
port: '443',
method: 'GET',
path: '/api/v1/topics?limit=1'
}
var req = https.request(options, function(res) {
// res.setEncoding('utf8')
var str = ''
res.on('data', function(data) {
str += data
})
res.on('end', function() {
// 解析为JSON格式
var res = JSON.parse(str)
if (res.success) {
console.log(res.data)
}
})
})
req.on('error', function(err) {
console.log(err)
})
req.end()
var https = require('https')
var qs = require('querystring')
// 把对象转化成可提交的字符串序列
var data = qs.stringify({
topic_id: '5ee1ee83b703280f0bcb922a',
_csrf: 'J5pSyVpb-DPf18zuVRoeoRa3YtjiTrDmSbow'
})
// 从cnode控制台复制这些内容
var options = {
hostname: 'cnodejs.org',
port: '443',
method: 'POST',
path: '/topic/collect',
headers: {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Content-Length": data.length,
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "connect.sid=s%3A2dTWSd1bfjY9aX2P42J6J4qzqEcyseoG.7V8fP85gjACREojrH9Bjtj2xF9F2YM%2BtYL3XyrBqd0I; _ga=GA1.2.1398122749.1594522616; _gid=GA1.2.956517977.1594522616; UM_distinctid=17340f43fdc31e-022e9f653e2209-3b634404-13c680-17340f43fdd722; CNZZDATA1254020586=1635525188-1594522618-https%253A%252F%252Fwww.baidu.com%252F%7C1594522618; node_club=s%3A5ac19da10ab0448f0fe3f7b2%24%24%24%24.c4TPrsdd%2B35kjylMrYe%2FaVl169ApEpHrl%2BaM0BUNUOI; _gat=1",
"Host": "cnodejs.org",
"Origin": "https://cnodejs.org",
"Referer": "https://cnodejs.org/topic/5ee1ee83b703280f0bcb922a",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
"X-CSRF-Token": "J5pSyVpb-DPf18zuVRoeoRa3YtjiTrDmSbow",
"X-Requested-With": "XMLHttpRequest"}
}
// 创建请求对象
var req = https.request(options, function(res) {
var ret = ''
res.on('data', function(data) {
ret += data
})
res.on('end', function() {
console.log(ret)
})
})
req.on('error', function(err) {
console.log('err', err)
})
5、events模块、事件触发器
如何创建一个事件触发器?
var EventEmitter = require('events')
var myEvent = new EventEmitter()
如何定义事件监听器?
myEvent.on('xxx', fn)
myEvent.once('xxx', fn)
如何触发事件?如何传递事件参数?
myEvent.emit('xxx', args)
6、fs模块,文件(夹)的增删改查
与文件夹相关的操作:创建、改名称、读、删
与文件相关的操作:写、读、删、改名称
//fs.stat
var fs = require('fs');
// 获取文件信息
fs.stat('package-lock.json', function(err, stats) {
console.log(stats.isFile())
console.log(stats.isDirectory())
})
//fs.mkdir
var fs = require('fs');
fs.mkdir('logs', function(err) {
if (!err) {
console.log('目录创建成功')
}
})
//fs.writeFile,fs.appendFile
var fs = require('fs');
var filePath = 'logs/hello.txt'
var text = "写入文件的内容\n"
// 异步 覆写
fs.writeFile(filePath, text, function(err) {
if (!err) {
console.log('成功写入文件')
}
})
// 异步 追加写入文件
fs.appendFile(filePath, text, function(err) {
if (!err) {
console.log('成功写入文件')
}
})
//fs.readFile
var fs = require('fs');
var filePath = 'logs/hello.txt'
// 第一种写法
fs.readFile(filePath, function(err,data) {
if(!err) {
// 编码格式转化
console.log(data.toString())
}
})
fs.readFile(filePath, 'utf-8', function(err,data) {
if(!err) {
console.log(data)
}
})
//fs.readdir
var fs = require('fs');
// 读取文件目录
fs.readdir(__dirname, function(err, files) {
if (!err) {
console.log(files)
}
})
//fs.rename
var fs = require('fs');
var filePath = 'logs/hello.txt'
var newName = 'logs/greet.txt'
fs.rename(filePath, newName, function(err) {
if(!err) {
console.log('文件名称修改成功')
}
})
// 不仅可以修改文件名
// 还可以修改文件夹的名字
var fs = require('fs');
// 遍历,删除文件
fs.readdirSync('logs').map(function(file) {
// 注意,要使用同步方法
fs.unlinkSync('logs/'+file, function(err) {
console.log('文件遍历 删除成功')
})
})
// 删除文件夹
// 注意,当文件夹不为空时,是无法删除的
fs.rmdirSync('logs', function(err) {
if(!err) {
console.log('目录删除成功')
} else {
console.log(err)
}
})
7、stream模块
为什么需要使用流?
当文件较大时,避免一次性把数据读入到内存,所以使用流批量读取文件数据。
.pipe() 管道流的使用
var fs = require('fs');
var inp = fs.createReadStream('package-lock.json')
var out = fs.createWriteStream('logs/a.txt');
//把inp文件写入out位置
inp.pipe(out);
8、path模块
path.join() //路径拼接
path.resolve() //将路径或路径片段的序列解析为绝对路径
Node.js原生Api 搭建服务器
1、什么是服务器?
提供服务的程序或设备,它的功能有接收并处理请求,处理并响应数据信息。
- 接收客户请求
- 处理请求
- 响应请求
2、Node.js原生路由实现WebServer
原理,就是根据 req.url 来区分客户的请求路径,根据不同的访问路径响应不同内容。
nodejs代码实时编辑工具:nodemon
res.writeHead(200, {'Content-Type':'text/plain;charset=utf-8;'})
参见:HTTP媒体类型/MIME_Types
项目需求描述:
使用node.js原生代码,实现图片、HTML/CSS/JS文件的访问
var http = require('http')
var fs = require('fs')
var path = require('path')
var server = http.createServer(function(req, res) {
var url = req.url
// favicon.ico
if (url != '/favicon.ico') {
// url路径处理
// 当用户直接访问 根路径 时
url = url === '/' ? '/index.html' : url
var filePath = path.join(__dirname, '/public' + url)
// 判断是不是文件
fs.stat(filePath, function(err, stats) {
// 报错、或文件不存在时
if (err || !stats) {
res.writeHead(404, {'Content-Type':'text/plain;charset=utf-8;'})
res.end('文件不存在 ')
}
// 如果是一个文件
if (stats && stats.isFile()) {
res.statusCode = 200
res.setHeader('Content-text', 'text/plain;')
// 读取文件,响应给客户端
fs.createReadStream(filePath).pipe(res)
}
})
}
})
// 端口监听
server.listen(8000, function() {
console.log('server is running on 8000')
})
用Express 重构WebServer
Express安装:npm install express -S
实现静态资源服务器static
var express = require('express')
var app = express()
// 静态服务,在根目录创建 public 目录,把静态资源放进去
app.use(express.static('public'))
// 路由
app.get('/', (req, res) => {
res.send('hello world')
})
// 端口监听
app.listen(8000, ()=>{
console.log('server in running on 8000')
})