什么是Node.js
Node.js可以解析Js代码(没有浏览器安全级别的限制)提供很多系统级别的API,如:
-文件的读写
-进程的管理
-网络通信
开发环境配置
下载:https://nodejs.org/en/
确认Node环境是否安装成功
查看node的版本号:
node --version或者node -v
模块/包/与CommonJS
1、文件读写
/*
**fs是file-system的简写,就是文件系统的意思
**例如 fs.readFile就是用来读取文件的
*/
const fs = require('fs');
//writeFile存在文件则进行覆盖,不存在则创建
fs.writeFile('./log.txt','hello',(err,data)=>{
if(err){
console.log('文件创建失败');
}else{
console.log('文件创建成功');
}
})
//readFile异步读取只能读取文件
fs.readdir('./',(err,data)=>{
if(err){
console.log(err.Error);
}else{
console.log('文件读取成功');
}
})
2、进程的管理(Process)
console.log(process.argv.slice(2));
3、网络通信
//引入http模块
const http = require('http');
//创建一个HTTP服务器 request:请求对象 response:响应对象
const server = http.createServer((request,response)=>{
let url = request.url;
response.write(url);
response.end();
})
server.listen(8090,'localhost',()=>{
console.log('localhost:8090')
})
4、URL
const url = require('url');
const querystring = require('querystring');
const urlString = 'https://www.cnblogs.com/xiongdongdong/p/11398466.html?id=6';
//url.parse()解析地址获取具体信息
console.log(url.parse(urlString));
//url.formeat()将一个解析后的URL对象、转成、一个格式化的URL字符串
let formeat = {
protocol: 'https:',
slashes: true,
auth: null,
host: 'www.cnblogs.com',
port: null,
hostname: 'www.cnblogs.com',
hash: null,
search: '?id=6',
query: 'id=6',
pathname: '/xiongdongdong/p/11398466.html',
path: '/xiongdongdong/p/11398466.html?id=6',
href: 'https://www.cnblogs.com/xiongdongdong/p/11398466.html?id=6'
}
console.log(url.format(formeat));
//url.resolve()替换 域名后面第一个“/”后的内容
let a = url.resolve('/one/two/three', 'four') ,
b = url.resolve('http://example.com/', '/one'),
c = url.resolve('http://example.com/one', '/two');
console.log(a +","+ b +","+ c);
/*
querystring模块用于解析与格式化url查询字符串
它提供了四个方法,分别是:querystring.parse, querystring.stringify, querystring.escape和querystring.unescape;
*/
// 1、querystring.parse(string, separator, eq, options),该方法是将一个字符串反序列化为一个对象。
// string: 指需要反序列化的字符串;
// separator(可选): 指用于分割字符串string的字符,默认为 &;
// eq(可选): 指用于划分键和值的字符和字符串,默认值为 "=";
// options(可选): 该参数是一个对象,里面可设置 maxKeys 和 decodeURIComponent 这两个属性。
console.log(querystring.parse(formeat.query));
// 2、querystring.stringify(obj, separator, eq, options),该方法是将一个对象序列化成一个字符串。
// 参数:obj指需要序列化的对象;
// separator(可选),用于连接键值对的字符或字符串,默认为 &;
// eq(可选),用于连接键和值的字符或字符串,默认值为 "=";
// options(可选),传入一个对象,该对象设置 encodeURIComponent这个属性;
console.log(querystring.stringify(formeat));
//3、querystring.escape(str)escape该方法可使传入的字符串进行编码
const char = "name=小明&sex=男";
const res = querystring.escape(char);
console.log(res); // 输出 name%3D%E7%A9%BA%E6%99%BA%26sex%3D%E7%94%B7
//4、querystring.unescape(str)该方法是对 使用了 escape编码的字符进行解码
const res2 = querystring.unescape(res);
console.log(res2); // name=空智&sex=男
5、爬虫案例练习
//引入http模块
const http = require('http');
//引入https模块
const https = require('https');
//引入cheerio模块
const cheerio = require('cheerio');
//待爬取的地址目标
let url = 'https://www.lagou.com/';
//对html数据做处理
const filterMenu = (html)=>{
let $ = cheerio.load(html);
let menu = $('.menu_main');
let menuData = [];
menu.each((index,value)=>{
//获取一级菜单
let menuTitle = $(value).find('h2').text();
//获取二级菜单
let menuList = $(value).find('a');
let menuLists = [];
menuList.each((index,value)=>{
menuLists.push($(value).text());
})
menuData.push({
menuTitle:menuTitle,
menuList:menuLists
})
})
return menuData
}
//打印回显
const printMenu = (menu)=>{
menu.forEach((value)=>{
console.log(value.menuTitle+'\n');
value.menuList.forEach((value)=>{
console.log(value);
})
})
}
https.get(url,(res)=>{
let html = '';
res.on('data',(data)=>{
html += data
})
res.on('end',()=>{
// console.log(html);
let result = filterMenu(html);
printMenu(result);
})
res.on('error',(err)=>{
console.log(err);
})
})
6、Http Request
const { response } = require('express');
const https = require('https');
let options = {
hostname:'douban.uieee.com',
port:443,
method:"GET",
path:'/v2/movie/coming_soon'
}
let request = https.request(options,(response) => {
console.log(response);
})
request.on('error',(err) => {
console.log(err);
})
request.end();
7、流应用
为什么要需要流?
当我们学习新知识的时候,首先我们知道为什么要学习,那我们为什么要学习流?因为在在node中读取文件的方式有来两种,一个是利用fs模块,一个是利用流来读取。如果读取小文件,我们可以使用fs读取,fs读取文件的时候,是将文件一次性读取到本地内存。而如果读取一个大文件,一次性读取会占用大量内存,效率很低,这个时候需要用流来读取。流是将数据分割段,一段一段的读取,可以控制速率,效率很高,不会占用太大的内存。gulp的task任务,文件压缩,和http中的请求和响应等功能的实现都是基于流来实现的。因此,系统学习下流还是很有必要的
const fs = require('fs');
/*
流都是基于原生的fs操作文件的方法来实现的,通过fs创建流。所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:
open -打开文件
data -当有数据可读时触发。
error -在读收和写入过程中发生错误时触发。
close -关闭文件
end - 没有更多的数据可读时触发
*/
//createReadStream 为可读流 createWriteStream为可读写流
let fileReadStream = fs.createReadStream('data.json',{
highWaterMark:3, //文件一次读多少字节,默认 64*1024
flags:'r', //默认 'r'
autoClose:true, //默认读取完毕后自动关闭
start:0, //读取文件开始位置
end:3, //流是闭合区间 包含start也含end
encoding:'utf8' //默认null
});
let count = 0;
//监听数据变化
fileReadStream.on('data',(chunk) => {
console.log(`${++count} 接收到:${chunk.length}`);
})
//在读收和写入过程中发生错误时触发
fileReadStream.on('error',(err) => {
console.log(err);
})
//读取结束时触发
fileReadStream.on('end',() => {
console.log('结束了')
})
8、node创建后端路由
const http = require('http');
const url = require('url');
//引入路由文件
let router = require('./router_1');
//创建http服务器
http.createServer((req,res) => {
/*
向请求的客户端发送响应头。
该函数在一个请求内最多只能调用一次,如果不调用,则会自动生成一个响应头。
*/
res.writeHead(200,{'Content-Type':'text/html; charset=utf-8'});
if(req.url !== '/favicon.ico'){
let pathName = url.parse(req.url).pathname.replace(/\//,'');
try{
router[pathName](req,res);
}catch{
router['home'](req,res);
}
}
res.end();
}).listen(3000);
console.log('Server running at http://localhost:3000');