温故node.js,node.js学习实操过程及笔记~
点击安装,傻瓜式安装。
nvm
方式安装node.js
,这样可实现自由切换版本好。因为有的老项目node.js可能是12版本的,新项目又是18或者20版本。具体安装自行查阅,目前这边已经安装,忘记哪个博主写的较好就不推荐了。
检测安装是否成功,输入以下命令到命令行,出来版本号代表安装成功
node -v
console.log("hello node.js!");
node + 文件路径
=》hello.js是相对文件路径,这里省略了./hello.js
node hello.js
// BOM不可用
console.log(window);
console.log(history);
console.log(navigator);
console.log(location)
//DOM不可用
console.log(document);
//global可用 globalthis可用
console.log(global)
//定时器可用
setTimeout(()=>{
console.log('hello~')
})
node.js内置模块Buffer,不需引入,理解为全局变量
//1.alloc
let buf = Buffer.alloc(10);
console.log(buf);
console.log('-------')
// 2.allocUnsafe;
let buf_2 = Buffer.allocUnsafe(10000);
console.log(buf_2);
console.log('-------')
//3.from
//打印出ASCII码字符代码表的值
let buf_3 = Buffer.from('hello');
console.log(buf_3);
console.log('-------');
//打印出二进制的值
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
console.log(buf_4);
console.log('-------');
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
console.log(buf_4);
console.log('-------');
//1-字符串转换 默认采用utf-8方式转换
const str = buf_4.toString();
console.log(str);
let buf_5 = Buffer.from('hello');
//1-[]括号方式进行单个元素的查看 二进制转换的查看
console.log(buf_5[0]);//打印出十进制
console.log(buf_5[0].toString(2));//实际上是01101000
//2-单个元素的修改
// 直接修改
buf_5[0] = 95;
//查看修改后的字符串的值
console.log(buf_5.toString());//输出_ello
//溢出
buf_5[0] = 361;//舍弃高位超出8位的数字 0001 0110 1001
console.log(buf_5);//69 0001被舍弃,留下0110 1001
//中文
let buf_6 = Buffer.from('你好');//utf-8编码方式 1个汉字对应3个中文
console.log(buf_6);//输出
安装好上面CPU等,还需安装操作系统方可运行。 操作系统:
操作系统也是一种应用程序,用来管理和调度硬件资源。将操作系统安装到硬盘,电脑即可开机运行。
常见操作系统
进程包含一个或多个线程。进程>线程
全称:file system 文件系统。fs模块可以实现与硬盘的交互。
例如文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的操作。
writeFile
(file,data[,option],callback)同步与异步
异步:情况比如做饭,按下了煮饭键就去炒菜。同步:类似排队,一个完成接着一个。对效率要求高的基本都是用异步API。
writeFile
(file,data[,option],callback)writeFileSync
(file,data[,option])/** 需求
* 新建一个文件夹为座右铭.txt(info.txt)
* 写入内容为 三人行,必有我师焉。
*/
const fs = require("fs");
//写入文件 异步写入
fs.writeFile('./info.txt', '三人行,必有我师焉!', (err) => {
if (err) {
console.error("写入错误:")
console.error(err);
return;
}
console.log("写入成功!")
})
//写入文件
// 同步写入
fs.writeFileSync('./infoSync.txt', '测试同步写入');
// 流式写入
const ws = fs.createWriteStream('./writeStream.txt');
ws.write('床前明月光\r\n');
ws.write('疑是地上霜\r\n');
ws.write('举头望明月\r\n');
ws.write('低头思故乡\r\n');
//关闭
ws.end();
文件追加多用于
程序日志
,不断往文件追加内容
方法 | 说明 |
---|---|
fs.appendFile (file,data[,option],callback) |
异步追加 |
fs.appendFileSync (file,data[,option]) |
同步追加 |
fs.writeFile (file,data[,option],callback) |
添加标识异步追加option为{flag:'a'} |
// 文件追加写入
const fs = require('fs');
// 异步追加
fs.appendFile('./info.txt', '\r\n哈哈哈追加内容下!', err => {
if (err) {
console.error(err);
return;
}
console.log('追加内容成功!')
})
//同步追加内容
fs.appendFileSync('./infoSync.txt', '\r\n同步追加内容看看!');
// 异步追加内容
fs.writeFile('./info.txt', '\r\n哈哈哈writeFile追加!', {flag: 'a'}, err => {
if (err) {
console.error('追加错误:');
console.error(err);
return;
}
console.log('追加成功!')
})
程序打开一个文件需要消耗资源
,流式写入可以减少文件的次数。
流式写入方式适用于大文件写入或者频繁写入
的场景,writeFile适用于写入频率较低的场景
。
参数说明:
返回值 Object
代码示例:
//写入文件
// 同步写入
fs.writeFileSync('./infoSync.txt', '测试同步写入');
// 流式写入
const ws = fs.createWriteStream('./writeStream.txt');
ws.write('床前明月光\r\n');
ws.write('疑是地上霜\r\n');
ws.write('举头望明月\r\n');
ws.write('低头思故乡\r\n');
//关闭
ws.end();
当需要持久化保存数据
的时候,应该想到文件写入
程序从文件中取出其中的数据。
方法 | 说明 |
---|---|
fs.readFile (file,data[,option],callback) |
异步读取 |
fs.readFileSync (file,data[,option]) |
同步读取 |
fs.createReadStream (file,data[,option],callback) |
流式读取 |
代码示例:
// 文件读取
const fs = require('fs');
// 异步读取
fs.readFile('./info.txt', (err, data) => {
if (err) {
console.error('读取错误:');
console.error(err);
return;
}
console.log('读取成功!')
console.log(data.toString());
})
console.log('-----------------');
// 同步读取
const readDataSync = fs.readFileSync('./infoSync.txt');
console.log('同步读取:')
console.log(readDataSync.toString());
console.log('-----------------');
// 流式读取
// 创建视频流对象
const rs = fs.createReadStream('./writeStream.txt');
// 绑定data事件 chunk 块
rs.on('data', chunk => {
console.log('---------!!----------');
// 字符串类文件读取可以,要是读取的的mp4文件,用toString输出将会乱码,直接console.log(chunk)即可
console.log(chunk.toString());
console.log('---------!!----------');
})
// end可选事件
rs.on('end', () => {
console.log('流式读取完成!');
})
代码示例:
/** fs练习_复制文件
* 将writeSteam.txt内容复制,新建writeStreamCopy.txt
*/
// 思路
// 1- readFile读取内容
// 2- writeFile新建文件
// 1、同步读取写入
const fs = require('fs');
// 读取
const readDataCopy = fs.readFileSync('./writeStream.txt');
// 写入
fs.writeFileSync('./writeStreamCopy.txt', readDataCopy);
console.log('测试内存:');
// PS:注释下面流式读取 得出内存
console.log(process.memoryUsage());// 28119040字节 ➗1024 约等于 281366.25kb ➗1024 约等于 274.78Mb
console.log('------------------------');
// 2、流式读取写入
//创建读取流对象
const rsCopy = fs.createReadStream('./writeStream.txt');
// 创建写入流对象
const wsCopy = fs.createWriteStream('./writeStreamCopyStream.txt');
// 1-绑定data事件
rsCopy.on('data', chunk => {
wsCopy.write(chunk);
})
// 2-on('data')方法复制或直接使用 管道 直接复制
// rsCopy.pipe(wsCopy);
// rsCopy.on('end', () => {
// console.log('测试内存:');
// // PS:注释上面直接读取 得出内存
// console.log(process.memoryUsage());// 28434432字节 ➗1024 约等于 27768kb ➗1024 约等于 27.117Mb
// console.log('------------------------');
// })
rename
(oldPath,newPath,callback)renameSync
(oldPath,newPath)参数说明
代码示例:
// fs重命名
const fs = require('fs');
//重命名:将文件1重命名为infoRename.txt
fs.rename('./info.txt', './infoRename.txt', err => {
if (err) {
console.error('重命名失败:');
console.error(err);
return;
}
console.log('重命名成功!');
})
// 确保目标目录存在
if (!fs.existsSync('./file')) {
fs.mkdirSync('./file');
}
// 移动:将重命名后的文件1移动到file文件夹,命名为info.txt
fs.rename('./infoSync.txt', './file/infoMove.txt', err => {
if (err) {
console.error('移动失败:');
console.error(err);
return;
}
console.log('移动成功!');
})
异步删除语法 fs.unlink
(path,callback)
同步删除语法fs.unlinkSync
(path)
异步删除fs.rm
(path,callback) ps:node.js14.4版本以上才可用
同步删除fs.rmSync
(path) ps:node.js14.4版本以上才可用
参数说明:
代码示例:
// 文件删除
const fs = require('fs');
//unlink删除
fs.unlink('./info.txt', (err) => {
if (err) {
console.error(err);
return;
}
console.log('删除成功!');
})
fs.unlinkSync('./infoSync.txt');
// rm删除 node.js14.4版本以上
fs.rm('./writeStream.txt', (err) => {
if (err) {
console.error(err);
return;
}
console.log('删除成功2!');
})
fs.rmSync('./writeStreamCopyStream.txt');
mkdir/mkdirSync
readdir/readdirSync
rmdir/rmdirSync
方法 | 说明 |
---|---|
mkdir/mkdirSync | 创建文件夹 |
readdir/readdirSync | 读取文件夹 |
rmdir/rmdirSync | 删除文件夹 |
PS:判断文件夹是否存在
参数说明:
mkdir
(path,callback)mkdirSync
(path)代码示例:
// 文件夹操作_创建文件夹
const fs = require('fs');
// 创建文件
//先判断是否存在
if (!fs.existsSync('./newFile')) {
fs.mkdir('./newFile', err => {
if (err) {
console.log('创建失败:');
console.error(err);
return;
}
console.log('创建成功');
})
}
//先判断是否存在
if (!fs.existsSync('./a/b/c', {recursive: true})) {
// 递归创建文件夹
fs.mkdir('./a/b/c', {recursive: true}, err => {
if (err) {
console.log('创建失败2:');
console.error(err);
return;
}
console.log('创建成功2');
})
}
//先判断是否存在
if (!fs.existsSync('./test2/d/e', {recursive: true})) {
fs.mkdirSync('./test2/d/e', {recursive: true});
}
readdir
(path,callback)readdirSync
(path)参数说明:
代码示例
// 文件夹操作——读取文件夹
const fs = require('fs');
// 创建文件
fs.readdir('./newFile', (err, data) => {
if (err) {
console.log('读取文件夹失败:');
console.error(err);
return;
}
console.log('读取文件夹成功');
console.log(data);
})
// 读取文件夹
fs.readdir('./file', (err, data) => {
if (err) {
console.log('读取文件夹失败2:');
console.error(err);
return;
}
console.log('读取文件夹成功2');
console.log(data);
})
const readfileData = fs.readdirSync('./test2');
console.log('同步读取文件夹');
console.log(readfileData);
不推荐使用rmdir
rmdir
(path,callback)rmdirSync
(path)推荐使用rm
:
rm
(path,callback)rmSync
(path)参数说明:
代码示例:
// 删除文件夹
const fs = require('fs');
//递归删除 不推荐使用rmdir 推荐使用rm
fs.rmdir('./a',{ recursive: true }, (err) => {
if(err){
console.log('删除文件夹出错');
console.error(err);
return;
}
console.log('删除文件夹成功!');
})
fs.rmdirSync('./test2', {recursive: true});
//rm删除
fs.rm('./newFile',{ recursive: true }, (err) => {
if(err){
console.log('删除文件夹出错2:');
console.error(err);
return;
}
console.log('删除文件夹成功2!');
})
fs.rmSync('./test', {recursive: true});
stat
(path[,option],callback)statSync
(path[,option])参数说明:
示例代码:fs_stat.js
/** 查看资源状态
* fs.stat()
*/
const fs = require('fs');
// 异步获取状态
fs.stat('./info.txt', (err, data) => {
if(err){
console.log('查看资源失败:')
console.log(err);
return;
}
console.log('异步查看资源成功!详细信息如下:')
console.log(data);
//判断是否是一个文件方法 isFile()
console.log('是文件吗?')
console.log(data.isFile());
// 判断是否是一个文件夹方法 isDirectory()
console.log("是文件夹吗?")
console.log(data.isDirectory());
})
// 同步获取状态
const data = fs.statSync('./info.txt');
console.log('同步查看资源成功!详细信息如下:')
console.log(data);
结果值对象结构:
路径分为
相对路径
和绝对路径
两种写法
比如在当前根目录的info.txt
./info.txt
相对路径参照的是命名行的工作目录!
Bug:
比如在 代码利用相对路径创建文件./info.txt
:
node fs_writeFile.js
就在当前文件夹生成info.txtnode ./nodejs/fs_writeFile.js
就会在nodejs同级生成info.txt结论:
解决方法
__dirname
进行拼接:保存的是所在文件的所在目录的绝对路径
代码示例:
//使用绝对路径:__dirname拼接方式
//利用绝对路径:使用全局变量`__dirname`进行拼接:保存的是所在文件的所在目录的`绝对路径`
fs.writeFileSync(__dirname+'/index.html','写入内容哈哈哈哈')
常会遇到权限的问题
比如在D盘下的info.txt
D:/info.txt
/
开头,比如/info.txt
优化如下:
__dirname
使用了绝对路径示例代码:
/** 批量重命名
* 需求:将code文件夹里面的文件
* 名称为前面为1-9的命名为01-09
*/
// 思路
// 1-读取readdirSync里面的文件名称 fs.readdirSync(path,callback)
// 2-重命名renameSync fs.renameSync(path,callback)
const fs = require('fs');
const files = fs.readdirSync(__dirname + '/code');
console.log('名称为:');
console.log(files);
// 读取文件修改
files.forEach(file => {
const oldPath = __dirname + '/code/' + file;
// 利用正则表达式_前面是一位数的补0
const newFileName = file.replace(/^(\d)_(.+)$/i, "0$1_$2");
const newPath = __dirname + '/code/' + newFileName;
//重命名
fs.renameSync(oldPath, newPath);
})
path模块提供了操作路径的功能。
API | 说明 |
---|---|
path.resolve |
拼接规范的绝对路径 常用 |
path.sep |
获得操作系统的路径分隔符 |
path.parse |
解析路径并返回对象 |
path.basename |
获得路径基础名称 |
path.dirname |
获得路径目录名 |
path.extname |
获得路径扩展名 |
代码示例:
// path模块
const fs = require('fs');
const path = require('path');
// 写入文件
// 建议绝对路径 +拼接+ 相对路径 写法 path.resolve(绝对路径+相对路径)
fs.writeFileSync(path.resolve(__dirname, './test.txt'), 'peace and love');
// 不建议这样写 最好不要 绝对路径+绝对路径写法 /path为绝对路径
// 这样写的意思是 /path的绝对路径 +拼接+ ./test.txt
// fs.writeFileSync(path.resolve(__dirname, '/path', './test.txt'), 'peace and love');
运行命令
node ./path/path.js
sep分隔符 :不同操作系统的分隔符不同,获取不同操作系统下的分隔符
操作系统 | 分隔符 |
---|---|
windows | \ |
linux | / |
macos | / |
代码示例:
const path = require('path');
// sep分隔符 :不同操作系统的分隔符不同,获取不同操作系统下的分隔符
console.log(path.sep); //windows:\ linux:/ macos:/
parse
(path)参数说明:
代码示例:
// parse 解析路径并返回对象
// 查看当前文件路径
console.log(__filename);
//定义路径
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 解析路径
console.log(path.parse(str));
basename
(path)参数说明:
代码示例:
// basename 获取路径名称
// 查看当前文件路径
console.log(__filename);
//定义路径
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 获取的文件名
console.log(path.basename(str)); //path.js
dirname
(path)参数说明:
代码示例:
// dirname 获取文件目录名
// 查看当前文件路径
console.log(__filename);
//定义路径
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 获取文件目录名
console.log(path.dirname(str)); // /Users/lhm/Documents/nodejs/path
extname
(path)参数说明:
代码示例:
// extname 获取文件扩展名即为后缀名
// 查看当前文件路径
console.log(__filename);
//定义路径
let str = '/Users/lhm/Documents/nodejs/path/path.js'
// 获取文件扩展名
console.log(path.extname(str)); // .js
Hypertext Transfer Protocol
超文本传输协议
互联网应用最广泛的协议之一如 GET https://www.baidu.com/ HTTP/1.1
构成
常见方法如下:
方法 | 作用 |
---|---|
GET |
主要用于获取数据 |
POST |
主要用于新增数据 |
PUT/PATCH |
主要用于更新数据 |
DELETE |
主要用于删除数据 |
HEAD/OPTIONS/CONNECT/TRACE |
使用相对较少 |
全程 Uniform Resource Locator 统一资源定位符
比如:https://search.jd/com:443/search?keyword=oneplus&psort=12
https
search.jd.com
443
/search
?keyword=oneplus&psort=12
版本号 | 发布时间 |
---|---|
1.0 |
1996年 |
1.1 |
1999年 |
2 |
2015年 |
3 |
2018年 |
很多键值对组成,主要是记录浏览器很多相关的信息,记录与浏览器交互的行为。
点击跳转MDN查看请求头
用一个场景理解它。比如登录场景 ,发送post请求传过去的数据:username=111&password=asaj11212。这些即为请求体。
状态码 | 含义 |
---|---|
200 |
请求成功 |
403 |
禁止请求 |
404 |
找不到资源 |
500 |
服务器内部错误 |
响应状态的描述通常与状态码相关
状态码 | 状态描述 |
---|---|
200 |
OK |
403 |
Forbidden |
404 |
Not Found |
500 |
Internal Server Error |
点击查看更多状态码
跟请求头一样为键值对的形式,记录与服务器相关的一些内容。
点击查看更多响应头
响应体即响应的内容
常见的响应体格式有:
IP也称为[IP地址],本身是一个数字标识。例如 192.168.1.3。 通俗理解IP地址主要
用来寻找网络设备
,本身是32Bit的二进制数字。
作用:
IP的分类
类型 | 说明 |
---|---|
本地回环IP地址 | 127.0.0.1 ~ 127.255.255.255 |
局域网IP(私网IP) | 192.168.0.0 ~ 192.168.255.255 172.16.0.0~172.31.255.255 10.0.0.0 ~ 10.255.255.255 |
广域网(公网IP) | 除上述之外 |
端口:应用程序的数字标识。一台现代计算机有65536个端口(0~65535)。一个应用程序可以使用一个或多个端口。
通俗理解: 赶集的摊位的编号
好比 计算机理解的端口
作用:
代码示例:./http/createServer.js
// 创建服务
// 1.导入http模块
const http = require('http');
// 2.创建服务对象
const server = http.createServer((request, response) => {
//设置响应内容
response.end('Hello World! Hello node.js Server!');
});
// 3.监听端口,启动服务
server.listen(9000, () => {
console.log("Server started on port 9000...");
console.log('http://localhost:9000/');
})
ctrl + c
停止服务必须重启服务才能生效
response.setHeader('content-type','text/html;charset=utf-8')
使用较多
想要获取请求的数据,需要通过request
对象
含义 | 语法 | 重点掌握 |
---|---|---|
请求方法 | request.method | * |
请求http协议版本 | request.httpVersion | |
请求路径 | request.url | * |
请求头 | request.headers | * |
请求体 | request.on(‘data’,function(chunk){}) request.on(‘end’,function(){}); |
|
url请求路径 | const url = require(‘url’); url.parse(request.url).pathname; | * |
url查询字符串 | const url = require(‘url’); url.parse(request.url,true).query; |
注意事项:
代码示例:./http/request_header.js
ps:浏览器打开form.html输入提交进行测试
ps:当端口被占用,关闭其它运行9000端口的终端,或者修改运行端口号。
// 请求报文之请求头
//引入http模块
const http = require("http");
//创建服务对象
const server = http.createServer((request, response) => {
// 1-----请求头
//请求方法
console.log('请求方法');
console.log(request.method);
// 请求http版本
console.log('请求http版本');
console.log(request.httpVersion);
// 请求头
console.log('请求url');
console.log(request.headers.host);
// 请求路径
console.log('请求路径');
console.log(request.url);
})
//启动服务
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
代码示例:./http/request_content.js
ps:浏览器打开form.html输入提交进行测试
ps:当端口被占用,关闭其它运行9000端口的终端,或者修改运行端口号。
// 请求报文之请求体
//引入http模块
const http = require("http");
//创建服务对象
const server = http.createServer((request, response) => {
// ----请求体
// 定义请求体内容
let body = '';
request.on('data', (chunk) => {
body += chunk;
})
request.on('end', () => {
console.log('请求体内容:')
console.log(body);
console.log('--------end--------------')
response.end('hello world!');
})
})
//启动服务
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
注意事项:
2. 运行:当端口被占用,关闭其它运行9000端口的终端,或者修改运行端口号。
2. 在浏览器输入进行测试观察终端打印日志:点击跳转浏览器进行测试
代码示例:./http/request_url.js
// 请求报文之url
//引入http模块
const http = require("http");
const url = require("url");
//创建服务对象
const server = http.createServer((request, response) => {
// ----url
console.log('请求路径:')
console.log(url.parse(request.url).pathname);
console.log('查询字符串:')
console.log(url.parse(request.url,true).query);
console.log(url.parse(request.url,true).query.username);
console.log(url.parse(request.url,true).query.password);
console.log('---------------');
response.end('hello world!');
})
//启动服务
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
语法:new URL(input[,base])
点击了解更多new URL英文
点击了解更多new URL中文
注意事项:
代码示例:./http/request_newURL.js
// 请求报文之url
//引入http模块
const http = require("http");
//创建服务对象
const server = http.createServer((request, response) => {
// 2- 通过new URL方式获取
let url = new URL(request.url, 'http://localhost:9000');
console.log(url);
console.log('请求路径:')
console.log(url.pathname);
console.log('查询字符串');
console.log(url.searchParams.get('username'));
console.log('------------------')
})
//启动服务
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
注意事项:
/** http练习
* 需求
* 请求类型 get 地址/login 返回 “登录页面” 四字
* 请求类型 get 地址/reg 返回 “注册页面” 四字
*/
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'GET') {
let url = new URL(req.url, 'http://127.0.0.1:9000');
//设置中文防止乱码
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
if (url.pathname === '/login') {
res.end('登录页面');
} else if (url.pathname === '/reg') {
res.end('注册页面');
} else {
res.end('您当前访问页面不存在!');
}
} else {
res.end('您当前访问页面不存在!');
}
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000,');
})
作用 | 语法 |
---|---|
设置响应状态码 | response.statusCode |
设置响应状态描述 | response.statusMessage(用的非常少) |
设置响应头信息 | response.setHeader(‘头名’,‘头值’) |
设置响应体 | response.write(‘xx’);response.end(‘xx’); |
注意事项:
代码示例:
// 设置响应头
//引入http模块
const http = require("http");
//创建服务对象
const server = http.createServer((request, response) => {
// 设置响应
//响应状态码
response.statusCode = 200;
//设置响应状态信息
response.statusMessage = 'iloveyou';
// 设置响应头
// 设置编码格式 防止中文乱码
response.setHeader('content-type', 'text/html; charset=utf-8');
// 自定义响应头
response.setHeader('myHeaders', 'Authorization');
//响应体 write可有多个
response.write('哈哈哈哈 响应体');
response.write('哈哈哈哈2 响应体');
// 响应体 end 只有一个
response.end('bye!!')
});
//启动服务
server.listen(9000, () => {
console.log('server listening on port 9000,');
console.log("http://localhost:9000/");
})
注意事项:
代码示例:res.pratice.html + res_pratice.js
/** http响应练习
* 需求
* 搭建http服务,响应一个4行3列的表格
* 并且要求表格有 隔行换色效果,且点击单元格能高亮显示
*/
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
res.setHeader('content-type', 'text/html;charset=UTF-8');
const html = fs.readFileSync(__dirname+'/res_pratice.html');
res.end(html);
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000/');
})
1-先加载html
2-再根据html内容加载css、图片资源、js等
3-favicon.icon请求:浏览器默认行为:默认请求网站图标favicon.icon
4-ws请求:插件行为,使得网页实现自动刷新功能
接回之前的响应练习,现在需求是将css js分离开,单独引入资源
代码示例: res_pratice.js => 读取res_practice.html res_pratice.css pratice_click.js
/** http响应练习
* 需求
* 搭建http服务,响应一个4行3列的表格
* 并且要求表格有 隔行换色效果,且点击单元格能高亮显示
*/
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
//按路径区分 请求资源 进行 响应。不要都响应此html
const {pathname} = new URL(req.url, 'http://127.0.0.1')
if (pathname === '/') {
//注意:此响应头得在html里,否则可能会没效果
res.setHeader('content-type', 'text/html;charset=UTF-8');
const html = fs.readFileSync(__dirname + '/res_pratice.html');
res.end(html);
} else if (pathname === '/res_pratice.css') {
const css = fs.readFileSync(__dirname + '/res_pratice.css');
res.end(css);
} else if (pathname === '/pratice_click.js') {
const js = fs.readFileSync(__dirname + '/pratice_click.js');
res.end(js);
} else {
res.end('404 Not Found!
');
}
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000/');
})
对响应式练习的优化处理
__dirname+pathname
进行拼接,无需多次请求代码示例:
/** http响应练习
* 需求
* 搭建http服务,响应一个4行3列的表格
* 并且要求表格有 隔行换色效果,且点击单元格能高亮显示
*/
const fs = require('fs');
const http = require('http');
const server = http.createServer((req, res) => {
//按路径区分 请求资源 进行 响应。不要都响应此html
// const {pathname} = new URL(req.url, 'http://127.0.0.1')
// if (pathname === '/') {
// //注意:此响应头得在html里,否则可能会没效果
// res.setHeader('content-type', 'text/html;charset=UTF-8');
// const html = fs.readFileSync(__dirname + '/res_pratice.html');
// res.end(html);
// } else if (pathname === '/res_pratice.css') {
// const css = fs.readFileSync(__dirname + '/res_pratice.css');
// res.end(css);
// } else if (pathname === '/pratice_click.js') {
// const js = fs.readFileSync(__dirname + '/pratice_click.js');
// res.end(js);
// } else {
// res.end('404 Not Found!
');
// }
// 优化
const {pathname} = new URL(req.url, 'http://127.0.0.1')
const filename = pathname === '/' ? __dirname + '/res_pratice.html' : __dirname + pathname;
fs.readFile(filename, 'utf8', (err, data) => {
if (err) {
res.end('404 Not Found!
');
console.error(err);
return;
}
res.end(data);
})
});
server.listen(9000, () => {
console.log('Server started on port 9000,');
console.log('http://localhost:9000/');
})
绝对路径可靠性强,而且相对性容易理解,在项目中运用较多
形式 | 特点 |
---|---|
http://www.baidu.com | 直接向目标资源发送请求,容易理解。网站的外链会用到此形式。 |
//www.baidu.com | 与页面URL的协议拼接形成完整URL再发送请求。大型网站用的比较多 |
/web | 与页面URL的协议、主机名、端口拼接形成完整URL再发送请求。中小型网站 |
相对路径在发送请求时,需要与当前页面URL路径进行计算,得到完整URL后,再发送请求,学习阶段用的较多。
例如当前网页url为:http://www.atguigu.com/course/h5.html
形式 | 最终的URL |
---|---|
./css/app.css | http://www.atguigu.com/course/css/app.css |
js/app/js | http://www.atguigu.com/course/js/app.js |
…/img/logo.png | http://www.atguigu.com/img/logo.png |
…/mp4/show.mp4 | http://www.atguigu.com/mp4/show.mp4 |
包括但不限于以下场景:
媒体类型
通常称为Multipurpose Internet Mail Extension
或 MIME
类型)是一种标准,用来表示文档、文件或字节流的性质和格式。
mime 类型结构: [type]/[subType]
例如: text/html images/jpeg image/png application/json
HTTP服务可以设置响应头Content-Type
来表明响应体的MIME类型,浏览器会根据该类型决定如何处理资源
下面是常见的文件对应的mime类型
html: `text/html`
css:`text/css`
js:`text/javascript`
png:`images/png`
jpg:`images/jpeg`
gif:`images/gif`
mp4:`video/mp4`
mp3:`audio/mpeg`
json:`application/json`
对于未知的资源类型,可选择
application/actet-stream
类型,浏览器在遇到该类型响应时,会对该响应体类型进行独立存储,也就是我们常见的下载
效果
代码示例:./http/mime.js
// 设置mime
const http = require('http');
const path = require('path');
const server = http.createServer((req, res) => {
// 优化
const {pathname} = new URL(req.url, 'http://127.0.0.1');
const filepath = pathname === '/' ? __dirname + '/res_pratice.html' : __dirname + pathname;
// 得到后缀名
const extname = path.extname(filepath).slice(1);
// 根据请求文件后缀名,设置相应的mime
let mimes = {
html: 'text/html',
css: "text/css",
js: 'text/javascript',
png: 'images/png',
jpg: 'images/jpeg',
gif: 'images/gif',
mp4: 'video/mp4',
mp3: 'audio/mp3',
json: 'application/json'
}
// 获取对应类型
const type = mimes[extname];
// 判断
if (type) {
//解决乱码问题
if(extname==='html'){
res.setHeader('Content-Type', type+';charset=utf-8');
}else{
res.setHeader('Content-Type', type);
}
} else {
res.setHeader('Content-Type', 'application/actet-stream');
}
fs.readFile(filepath, 'utf8', (err, data) => {
if (err) {
res.end('404 Not Found!
');
console.error(err);
return;
}
res.end(data);
})
});
server.listen(9000, () => {
console.log('server started');
console.log('http://localhost:9000/');
})
charset:utf-8
即可.代码示例:如上:./http/mime.js
点击node.js中文网查看错误代码具体含义
代码处理示例:error.js
// 完善错误处理
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res) => {
// 优化
const {pathname} = new URL(req.url, 'http://127.0.0.1');
const filepath = pathname === '/' ? __dirname + '/res_pratice.html' : __dirname + pathname;
fs.readFile(filepath, 'utf8', (err, data) => {
if (err) {
console.error(err);
switch (err.code) {
case 'ENOENT':
res.statusCode = 404;
res.end('404 Not Found!
');
case 'EPERM':
res.statusCode = 403;
res.end('403 Forbidden!
');
default:
res.statusCode = 500;
res.end('Internal Server Error
');
}
return;
}
res.end(data);
})
});
server.listen(9000, () => {
console.log('server started');
console.log('http://localhost:9000/');
})
GET请求场景:
POST请求中的请求
GET和POST是HTTP协议请求中的两种方式,主要有以下区别:
将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为模块化
其中拆分出的每个文件就是一个模块。模块内部的数据是私有的,不过模块可以暴露内部数据以使其它模块使用
模块化项目:
编码时按照模块一个个编码的,整个项目就是一个模块化的项目
模块化好处:
代码示例:me.js
// 声明函数
function tiemo(){
console.log('timemo')
}
module.exports = tiemo;
代码示例:index.js
//引入模块
const tiemo = require('./me');
// 调用
tiemo();
运行:
node ./module/index.js
注意:不要直接exports = value ❎ 错误写法
代码示例: me.js
// 声明函数
function tiemo() {
console.log('timemo')
}
function niejiao() {
console.log('niejiao');
}
// 暴露数据
// module.exports = tiemo;
// 暴露数据2
module.exports = {
tiemo,
niejiao
}
// 暴露数据3
// exports.niejiao = niejiao;
// exports.tiemo = tiemo;
// 注意:不能使用 exports=value的形式暴露数据
// 因为如下相等
// exports = module.exports = {tiemo: tiemo}
// exports.tiemo = tiemo;
代码示例:index.js 调用
//引入模块
const me = require('./me');
// 调用
me.tiemo();
me.niejiao();
在模块中使用require
传入文件路径即可使用文件
const test = require('./me.js');
require
使用的一些注意事项
./
和../
package.json
文件中main属性对应的文件,如果main属性不存在,或者package.json不存在,则会检测文件夹下的index.js和index.json.如果还是没找到,就会报错./
和../
Node.js实现了CommonJS模块化规范
介绍require
导入自定义模块的基本流程
arguments.callee.toString()
查看自执行函数module.exports
exports
以及require
这些都是CommonJS模块化规范中的内容包管理工具就像
哆啦A梦
【包】英文单词 package 代表了一组特定功能的源码集合
包管理工具
管理【包】的应用软件,可以对【包】进行下载安装,更新,删除,上传等操作
常用的包管理工具
node.js在安装时会自动安装npm,若你已经安装了node.js,可以直接使用npm
npm -v
查看版本号测试。显示版本号即为成功,反之失败我在此新建了npm文件夹,并切换终端目录到npm,使用cd npm
切换到npm文件夹也可。
注意:
npm init -y
或者npm init --yes
极速
创建package.json方式2种
关于如何精准找到需要的包
这个事情需要在实践中不断积累,通过看文章,看项目去学习积累
npm install
简写 npm i
我们可以在安装时设置区分依赖的类型,目前分为两类
类型 | 命令 | 补充 |
---|---|---|
生产依赖 | npm i -S uniq npm i --save uniq |
-S等效于–save -S是默认选项 包信息保存在package.json中的dependencies属性 |
开发依赖 | npm i -D less npm i --save-dev less |
-D等效于–save-dev -S是默认选项 包信息保存在package.json中的devDependencies属性 |
比如蛋炒饭需要 大米 油 葱 鸡蛋 锅 煤气 铲子
其中 锅 煤气 铲子 属于开发依赖,只在制作阶段使用
而大米 有 葱 鸡蛋属于生产依赖 在制作与最终食用都会用
所以开发依赖是只在开发阶段使用的依赖包,而生产依赖是开发阶段和最终上线运行阶段都用到的依赖包
npm i -g nodemon
全局安装完成之后就可以在命令行的任何位置运行nodemon命令
该命令作用是自动重启node应用程序。【修改文件代码后不需关闭终端,重新运行,会自动监测编译】
使用nodemon运行即可
nodemon ./fs/fs_writeFile.js
与此同时修改./fs/fs_writeFile.js文件会自动编译,不需要关闭重新运行
注意:
npm root -g
查看全局安装包位置命令行输入命令会在当前目录寻找.exe或者.cmd后缀可执行文件执行,找到执行,找不到则报错。
比如输入QQ 会在当前文件夹寻找 QQ.exe或者QQ.cmd的可执行文件。找不到就去环境变量
中找,所以路径需配置在环境变量
中。
npm i
npm i <包名@版本包>
npm i [email protected]
npm remove
/ npm r
npm uninstall
/ npm uni
npm remove -g modemon
局部删除示例:
npm remove uniq
npm uninstall juery
- npm start 是项目中常用命令,用来启动命令。可不加 run
- npm run 有自动向上级目录查找的特性,跟require函数一样默认
- 对于陌生项目,我们可以先通过查看scripts属性来参考项目的一些操作。可看到怎么运行项目、打包项目等
示例如:(配置了start启动命令)
{
"name": "test",
"version": "1.0.0",
"description": "学习npm",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node ./test.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"uniq": "^1.0.1"
}
}
2.运行
npm run start
npmjs.com
的完整镜像,也称为【淘宝镜像】,网址阿里云服务器上
,可以提高的下载速度cnpm
,操作命令与npm大体相同npm install -g cnpm --registry=https://registry.npmmirror.com
功能 | 命令 |
---|---|
初始化 | cnpm init |
安装包 | cnpm i uniq cnpm i -S uniq cnpm i -D uniq cnpm i -g nodemon |
安装项目依赖 | cnpm i |
删除 | cnpm r uniq cnpm uni uniq |
用npm可直接下载淘宝镜像,配置方式有两种
npm config set registry https://registry.npmmirror.com/
npm i -g nrm
nrm use taobao
npm config list
PS: 检查registry地址是否为https://reggistry/npmmirror.com/ 如果是则表明成功
补充说明:
- 建议使用第二种方式进行镜像配置,因为后续修改起来会比较方便
- 虽然cnpm可以提高速度,但是npm也可以通过淘宝镜像进行加速,所以npm使用率还是高于cnpm
yarn是Facebook在2016年推出的JavaScript推出的包管理工具 官网网址
特点
npm i -g yarn
功能 | 命令 |
---|---|
初始化 | yarn init / yarn init -y |
安装包 | yarn add uniq 生产依赖 yarn add less --dev 开发依赖 yarn global add nodemon 全局安装 |
安装项目依赖 | yarn |
删除 | yarn remove uniq 删除项目依赖包 yarn global remove nodemon 全局删除包 |
运行命令别名 | yarn <别名> |
大家可以根据不同场景进行选择
包管理工具不要混用,切记,切记,切记
将自己开发的工具包发布到npm服务上,方便自己和其它开发者进行使用,操作步骤如下:
代码示例:
function add(a, b) {
return a + b;
}
module.exports = {
add
}
npm init
,package.json填写包的信息(包名必须唯一)通过nrm方式切回官方镜像:
没安装的先安装:
npm i -g nrm
切回官方镜像:
nrm use npm
npm login
npm publish
npm publish
npm unpublish
不成功加上--force
强制删除
npm unpublish --force
删除包需要一定条件,查看条件
很多语言都有包管理工具。除了编程语言,操作系统层面也存在包管理工具。
语言 | 包管理工具 |
---|---|
PHP | composer |
Python | pip |
Java | maven |
Go | go mod |
JavaScript | npm/yarn/cnpm/other |
Ruby | rubyGems |
操作系统也存在包管理工具,不过这个包指的是软件包:
操作系统 | 包管理工具 | 网址 |
---|---|---|
Centos | composer | https://package.debian.org/stabel/ |
Ubuntu | apt | https://package.ubuntu.com / |
MacOS | homeview | https://brew.sh / |
Windows | chocolatey | https://chocolatey.org |
nvm 全称 Node Version Manager 顾名思义用来管理node版本工具。方便切换不用版本的Node.js。一般项目中,新旧项目要求的node版本不同,建议使用nvm安装node.js,方便切换
安装太久,不知道哪个博文好使了,可以去网上寻找细致教程
nvm-setup.exe
下载即可命令 | 说明 |
---|---|
nvm use available | 显示可下载的Node.js版本 |
nvm list | 显示已安装的版本 |
nvm install 18.12.1 | 安装18.12.1版本的Node.js |
nvm install latest | 安装最新版本的Node.js |
nvm uninstall 18.12.1 | 删除18.12.1版本的Node.js |
nvm use 18.12.1 | 切换18.12.1的Node.js |
官网介绍:expresss是一个基于Node.js平台的极简、灵活的WEB应用开发框架。官网网址.简单来说,express是一个封装好的工具包,封装了很多功能,便于我们开发WEB应用。(HTTP服务)
http模块帮助我们搭建http服务,给浏览器做出相应服务端的功能,直接使用还是不太方面,于是我们借助express框架.
路由确定了应用程序如何响应客户对特定端点的请求。
一个路由有请求方法、路径和回调函数组成
express中提供了一系列方法,可以很方便的使用路由 使用格式如下:
app.(path,callback)
PS:代码中1-4方法使用,知识点
代码示例:startlearn.js
// 初认识express
// 引入模块
const express = require('express');
// 创建应用对象
const app = express();
const port = 3000;
// 1-创建路由 get方法
app.get('/home', (req, res) => {
res.end('hello world');
})
// 2-创建路由 get方法
app.post('/login', (req, res) => {
res.end('hello login');
})
//3- 无论get或post方法
app.all('/test', (req, res) => {
res.end('no matter methods');
})
//4-上面匹配不上的路由规则
app.all('*', (req, res) => {
res.end('404 No Found');
})
//监听端口 启动服务
app.listen(port, () => {
console.log('Express server started');
console.log('http://localhost:9000/');
})
说明 | 原生http获取 | express框架获取 |
---|---|---|
获取请求路径path | const url = require(‘url’); url.parse(request.url).pathname; / new URL(req.url,‘http://localhost:9000’).pathname |
req.path |
获取请求参数 | const url = require(‘url’); url.parse(request.url,true).query; | req.query |
获取ip | req.connection.remoteAddress | req.ip |
获取请求头 | req.headers[‘host’] | req.get(‘host’) |
/:id
通过req.params.id
获取路由参数代码示例:
const express = require('express');
const app = express();
//通配符 通过http://localhost:3000/login/1212121访问即可知
app.get('/login/:id', (req, res) => {
// 获取id
console.log(req.params.id);
res.end('login success!');
})
app.get('/', (req, res) => {
res.end('hello');
})
//监听端口 启动服务
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
})
运行后点击测试
代码示例如下:singer.json + params_pratice.js
/** 需求
* 通过路由id返回歌手名称及其它名称
*/
const express = require('express');
const app = express();
const fs = require('fs');
// 读取歌手假数据json文件
const singersData = fs.readFileSync(__dirname + '/singers.json').toString();
app.get('/singer/:id', (req, res) => {
const {id} = req.params;
const matchData = JSON.parse(singersData).singers.find(item => item.id === Number(id));
res.setHeader('content-type', 'text/html; charset=utf-8');
if (matchData) {
res.end(`名称:${matchData.singer_name},其它名称:${matchData.other_name}`);
} else {
res.end('No Such a Singer');
}
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
})
代码示例如下:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
// //原生响应也兼容
// res.statusCode = 200;
// res.statusMessage = 'asasa';
// res.setHeader('hahha', 'hhh');
// res.write('hello world!');
// res.end('res content');
// express设置状态码
// res.status(200);
// // express设置请求头
// res.setset('hahaha~', 'hhh');
// // express响应内容 做了封装 中文不乱码
// res.send('你好');
// 连贯操作
res.status(200).set('hahaha~', 'hhh').send('你好 express');
})
app.listen(3000, () => {
console.log('server started on port 3000');
console.log('http://localhost:3000');
});
// 其它响应
app.get('/other', (req, res) => {
//1-设置重定向
// res.redirect('http://www.baidu.com');
// 2-下载响应
// res.download(__dirname + '/singers.json');
// 3-响应json
// res.json({
// "singer_name": "林俊杰",
// "other_name": " JJ Lin",
// "id": 2
// });
//4-响应文件内容
res.sendFile(__dirname + '/test.html');
})
代码示例:middleware.js
// 认识中间件
/** 需求
* 追加日志记录,写入log.txt文件
*/
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
// 全局中间件
// 定义
function recordMiddleWare(req, res, next) {
// 判断是否有文件 没有就创建
const filePath = path.resolve(__dirname, './log.txt');
// 判断文件是否存在,如果不存在就创建一个空文件
if (!fs.existsSync(filePath)) {
fs.writeFileSync(filePath, '');
}
// 获取url和ip地址
const {url, ip} = req;
// 每个请求过来的路由信息都保存到日志记录文件
fs.appendFileSync(path.resolve(__dirname, `./log.txt`), `${url} ${ip}\r\n`);
// 调用next
next();
}
// 调用中间件函数
app.use(recordMiddleWare);
app.get('/login', (req, res) => {
res.send('login success!');
})
app.listen(3000, () => {
console.log('server started at port 3000');
console.log('http://localhost:3000');
})
代码示例:middleware_pratice.js
// 中间件实践
/** 需求
* 针对/admin /setting的请求,要求URL携带code=521参数,如未携带提示【暗号错误】
*/
const express = require('express');
const app = express();
// 定义中间件
function checkCodeMiddleWare(req, res, next) {
// 获取code
const {code} = req.query;
if (Number(code) === 521) {
next();
} else {
next("【暗号错误】");
}
}
//调用中间件
app.get('/admin', checkCodeMiddleWare, (req, res) => {
res.send('admin success!');
})
//调用中间件
app.get('/setting', checkCodeMiddleWare, (req, res) => {
res.send('setting success!');
})
app.get('/registry', (req, res) => {
res.send('registry success!');
})
app.get('*', (req, res) => {
res.send('404 Not Found
');
})
app.listen(3000, () => {
console.log('server started at port 3000');
console.log('http://localhost:3000');
})
//静态资源中间件请求
app.use(express.static(__dirname + '/public'));
node express/staticMiddleware.js
完整代码示例:
// 静态资源中间件
const express = require('express');
const app = express();
//静态资源中间件请求
app.use(express.static(__dirname + '/public'));
// 监听端口 启动服务
app.listen(3000, () => {
console.log("Server running on port 3000");
console.log('http://localhost:3000');
})
静态资源中间件注意事项
npm i body-parser
// 获取中间件函数
//处理queryString格式的请求体
const urlParser = bodyParser.urlencoded({extended: false});
//处理json格式的请求体
const jsonParser = bodyParser.json();
//获取请求体数据
app.post('/login', urlParser, (req, res) => {
// 获取请求体数据
console.log(req.body);
res.send('用户名:' + req.body.username + '
密码:' + req.body.password);
})
完整代码示例:bodyParser.js
// body-parse获取请求体
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
// 获取中间件函数
//处理queryString格式的请求体
const urlParser = bodyParser.urlencoded({extended: false});
//处理json格式的请求体
const jsonParser = bodyParser.json();
//响应login页面
app.get('/login', urlParser, (req, res) => {
res.sendFile(__dirname + '/login.html');
})
//获取请求体数据
app.post('/login', urlParser, (req, res) => {
// 获取请求体数据
console.log(req.body);
res.send('用户名:' + req.body.username + '
密码:' + req.body.password);
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
})
比如有的图片,直接复制地址显示到img是拿不到的,说明这个网站做了防盗链处理。判断源是请求头里的
referer
参数会携带当前域名和协议及其端口进行请求。
完整代码示例:
const express = require('express');
const app = express();
// 定义全局防盗链中间件 判断请求头referer
app.use((req, res, next) => {
const referer = req.get('referer');
if (referer) {
// 实例化
const url = new URL(referer);
const hostname = url.hostname;
console.log(hostname);
if (hostname !== '127.0.0.1') {
res.status(404).send('404 Not Found
');
return;
}
}
next();
})
// 读取静态资源
app.use(express.static(__dirname + '/public'));
app.listen(3000, () => {
console.log('Express server listening on port 3000');
console.log('http://localhost:3000');
})
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>测试!!h1>
<img src="http://127.0.0.1:3000/images/logo.jpeg" alt="logo">
body>
html>
路由功能代码进行拆分
const express = require("express");
const userRouter = require(__dirname + "/routes/userRouter.js");
const adminRouter = require(__dirname + "/routes/adminRouter.js");
const app = express();
app.use(userRouter);
app.use(adminRouter);
app.all("*", function (req, res) {
res.send('404 Not Found');
})
app.listen(3000, () => {
console.log("server started");
console.log('http://localhost:3000');
})
// user routes
const express = require('express');
const router = express.Router();
router.get('/login', (req, res) => {
res.send('login登录');
})
router.get('/registry', (req, res) => {
res.send('registry注册');
})
module.exports = router;
// admin routes
const express = require('express');
const router = express.Router();
router.get('/setting', (req, res) => {
res.send('设置setting');
})
router.get('/modify', (req, res) => {
res.send('修改setting');
})
module.exports = router;
分离HTML和JS的,ejs是一个高效的JavaScript模版引擎。主要了解ejs,现在不多用了。
npm i ejs
const ejs = require('ejs');
// ejs初体验
const express = require('express');
const ejs = require('ejs');
const fs = require('fs');
const path = require('path');
const app = express();
// 读取静态资源
app.use(express.static(path.join(__dirname, './public')));
const china = '中国';
// 读取html文件
const htmlData = fs.readFileSync(__dirname + '/public/index.html','utf-8').toString();
//使用ejs渲染
const result = ejs.render(htmlData, {china: china});
console.log(result);
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>测试!!h1>
<img src="http://127.0.0.1:3000/images/logo.jpeg" alt="logo">
<h1>读出来了吗?h1>
<h2><%= china %>h2>
body>
html>
代码如下:ejs_xiyou.js
// ejs列表渲染
/** 需求
* 渲染ul li 西游数组
*/
const ejs = require('ejs');
const fs = require('fs');
const xiyou = ['唐僧', '孙悟空', '沙僧', '猪八戒'];
const htmlData = fs.readFileSync(__dirname + '/ejs_xiyou.html').toString()
const result = ejs.render(htmlData, {xiyou: xiyou});
console.log(result);
代码如下:ejs_xiyou.html
<ul>
<% xiyou.forEach(item=>{ %>
<li> <%= item %>li>
<% }) %>
ul>
<% if(isLogin){ %>
<span>登录成功span>
<% }else{ %>
<span>登录失败span>
<% } %>
app.set('view engine', 'ejs');
app.set('views',path.resolve(__dirname,'./views'))
res.render('home',{title})
<%= title %>
完整代码示例:express_ejs.js
const express = require("express");
const ejs = require("ejs");
const path = require("path");
const app = express();
// 1-设置模版引擎
app.set("view engine", "ejs");
// 2-设置模版文件存放位置
app.set("views", path.resolve(__dirname, "./views"));
app.get('/home', (req, res) => {
const title = 'Home页面';
// 3-render响应
res.render("home", {title});
// 创建模版文件 home.ejs
})
app.all('*', (req, res) => {
res.send('404 Not Found');
})
app.listen(3000, () => {
console.log("Server is running on port 3000");
console.log('http://localhost:3000');
});
完整代码:views=>home.ejs
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<h1>测试:h1>
<h1><%= title %> h1>
body>
html>
npx express-generator
npm i -g express-generator
express -e generator
查看相关命令
express -h
const express = require('express');
const path = require('path');
const app = express();
//设置模板引擎
app.set('view engine', 'ejs');
//设置模板引擎存放文件位置
app.set('views', path.resolve(__dirname, './views'));
// render响应
app.get('/portrait', (req, res) => {
res.render('portrait');
})
app.post('/portrait', (req, res) => {
console.log(req);
res.send('成功!');
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
});
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>查看文件上传报文title>
head>
<body>
<form action="/portrait" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username"><br>
头像 <input type="file" name="portrait">
<button>点击提交button>
form>
body>
html>
require
引入需要安装V2
版本的,V3的只能使用import 引入代码示例:
const express = require('express');
const path = require('path');
const formidable = require('formidable').formidable;
const app = express();
//设置模板引擎
app.set('view engine', 'ejs');
//设置模板引擎存放文件位置
app.set('views', path.resolve(__dirname, './views'));
// render响应
app.get('/portrait', (req, res) => {
res.render('portrait');
})
// 响应静态资源——方便访问上传的图片
app.use(express.static(path.resolve(__dirname, './public')));
app.post('/portrait', (req, res) => {
const form = formidable({
multiple: true,
// 设置上传文件的保存目录
uploadDir: path.join(__dirname, './public/images'),
// 保持文件后缀
keepExtensions: true
})
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
// 存放非文件的字段
// console.log(fields);
// 存放文件
// console.log(files);
// 服务器保存存放的照片的访问url
const url = '/images/' + files.portrait.newFilename;
res.send(url);
});
})
app.listen(3000, () => {
console.log('Express server started');
console.log('http://localhost:3000');
});
基于分布式文件存储的数据库,官方网址
相比于纯文件管理数据,数据库管理数据优点:
下载地址
这边记录下自己的mac安装教程,可根据直接的电脑系统去搜搜安装
具体步骤:
export PATH=${PATH}:/usr/local/mongodb/bin
mongod --version
cd /usr/local/mongodb
mkdir data log
sudo chown [你的用户名] /usr/local/mongodb/data
sudo chown [你的用户名] /usr/local/mongodb/log
mongod --fork --dbpath data --logpath log/mongo.log --logappend
使用mongo指令
浏览器进入http://127.0.0.1:27017/
关闭数据库服务 (直接关闭)针对于(mac zsh)
sudo pkill -f mongod
创建一个启动脚本文件,以确保命令在正确的目录中运行:
touch start_mongo.sh
nano start_mongo.sh
#!/bin/zsh
cd /usr/local/mongodb
mongod --fork --dbpath data --logpath log/mongo.log --logappend
保存并退出:
保存文件并退出编辑器(按Ctrl+X退出,按Y保存,回车enter退出)。
PS:同理建立了关闭mongods脚本。
命令为:
sudo pkill -f mongod
chmod +x start_mongo.sh
./start_mongo.sh
db.user.insert({username:'ll',age:18})
db.user.find({age:20})
db.user.find({name:'张三'},{$set:{age:20}})
db.user.remove({name:'张三'})
代码及说明如下:
// mongoose使用 前提得启动mongoose
// 1-安装依赖
// 2-引入依赖
const mongoose = require('mongoose');
// 3-连接mongodb服务
mongoose.connect('mongodb://127.0.0.1:27017/user');
// 补充说明:1-设置strictQuery为true
mongoose.set('strictQuery', true);
// 设置回调
// 连接成功的回调 补充说明:2-once:事件回调函数只执行一次
mongoose.connection.on('open', () => {
console.log('连接成功!');
})
// 连接错误的回调
mongoose.connection.on('error', (err) => {
console.log('连接错误:')
console.error(err);
})
// 连接关闭的回调
mongoose.connection.on('close', () => {
console.log('连接关闭');
})
// 关闭连接
setTimeout(function () {
console.log('连接关闭');
mongoose.disconnect();
}, 2000)
…mongoose大致学到这里,需要的在看文档好了…
所谓会话控制是对会话进行控制。
因为HTTP是一个无状态的协议,它没有办法区分多次的请求是否来自同一客户端,无法区分用户,而产品中又大量存在这样的需求,所以我们需要通过会话控制解决该问题。
常见的会话控制方式:
cookie是HTTP服务器发送到用户浏览器并保存在本地的一小块数据
特点:
这个操作一般不做
cookie
(‘name’,‘lhm’,{})const express = require('express');
const app = express();
app.get('/set-cookie',(req,res)=>{
res.cookie('name','lhm');//会在浏览器关闭的时候,销毁
res.cookie('name','lhm',{maxAge:60 * 1000}); //maxAge最大存活时间 单位毫秒 但是浏览器中存的是秒s
res.send('home');
})
clearCookie
(‘name’)const express = require('express');
const app = express();
app.get('/remove-cookie',(req,res)=>{
res.clearCookie('name');
res.send('remove');
})
npm i cookie-parse
const express = require('express');
const cookieParse = require('cookie-parse');
const app = express();
app.use(cookieParse());
req.cookies
获取到cookie值app.get('/get-cookie',(req,res)=>{
console.log(req.cookies);
console.log(res.cookies.name);
})
保存到服务器的一块儿数据,保存当前访问的用户的相关信息
作用:
实现会话控制,可以识别用户的身份,快速获取当前用户的相关信息
运行流程:
视频的基础知识大致学到这里,下面似乎涉及用处小,需要的时候还有机会的话再更新吧…
完结撒花~~~