Node.js 学习笔记

Node.js 学习笔记_第1张图片

Node.js 学习笔记_第2张图片
在这里插入图片描述
小插件Template String Converter 当输入${}时,自动为其加上 `` 反引号Node.js 学习笔记_第3张图片

一、node入门

  1. node.js是什么
    Node.js 学习笔记_第4张图片

  2. node的作用

  3. 开发服务器应用

  4. 开发工具类应用
    Node.js 学习笔记_第5张图片

  5. 开发桌面端应用

1.命令行工具

  1. 命令的结构
    Node.js 学习笔记_第6张图片

  2. 常用命令

切换到D盘——D:
查看D盘目录——dir
切换工作目录——cd machine
输出文件夹内的所有内容——dir /s

  • cd 是change direct的缩写

[图片]

2.使用node运行js文件

js文件
Node.js 学习笔记_第7张图片

命令行操作
Node.js 学习笔记_第8张图片
在这里插入图片描述
直接在vscode的集成终端中操作
在这里插入图片描述

3.node注意事项

Node.js 学习笔记_第9张图片
Node.js 学习笔记_第10张图片
顶级对象global相当于浏览器环境的window在这里插入图片描述

4.Buffer 缓冲区

概念

  • 一个类似于Array的对象,用于表示固定长度的字节序列
  • 本质是一段内存空间,专门用来处理二进制数据。
    [图片]

特点

  • 大小固定,且无法调整(与数组不同,数组大小可以改变)
  • 性能较好,可以直接对计算机内存进行操作
  • 每个元素的大小为1字节
    Node.js 学习笔记_第11张图片

使用

let buf=Buffer.alloc(2)
console.log(buf)

let buf_2 =Buffer.allocUnsafe(11112)
//使用这种方式不一定会把旧的数据清空
//速度更快,不用进行清零操作
console.log(buf_2)

let buf_3 =Buffer.from('hello')
//把字符串的每个字符都转换成unicode
console.log(buf_3)

//终端显示

D:\web>node test.js
<Buffer 00 00>
<Buffer 80 00 df 3e 08 02 00 00 f0 fc 10 35 08 02 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ... 11062 more bytes>
<Buffer 68 65 6c 6c 6f>

D:\web>node test.js
<Buffer 00 00>
<Buffer 80 00 3b f5 be 02 00 00 80 63 34 f5 be 02 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ... 11062 more bytes>
<Buffer 68 65 6c 6c 6f>

可以发现:使用allocUnsafe每次的都不样

Node.js 学习笔记_第12张图片

4.1 与字符串的转换

let buf_4 =Buffer.from([105,108,111,118,101,121,111,117])
console.log(buf_4)
console.log(buf_4.toString())

//
D:\web>node test.js
<Buffer 69 6c 6f 76 65 79 6f 75>
iloveyou

4.2 Buffer 的读写

Buffer 可以直接通过 [] 的方式对数据进行处理。

//读取
console.log(buf_3[1]);
//修改
buf_3[1] = 97;
//查看字符串结果
console.log(buf_3.toString())

注意:

  1. 如果修改的数值超过 255 ,则超过 8 位数据会被舍弃
  2. 一个 utf-8 的字符 一般 占 3 个字节(如:中文)

5. 计算机的基本组成

Node.js 学习笔记_第13张图片

6. 程序运行的基本流程

Node.js 学习笔记_第14张图片
APP、数据——载入内存——CPU读取指令——显卡or 声卡——显示器or音箱。
在这里插入图片描述

7.进程、线程

  1. 进程打开任务管理器即可查看
    Node.js 学习笔记_第15张图片
  2. 线程是进程的组成部分。Node.js 学习笔记_第16张图片
    Node.js 学习笔记_第17张图片

查看QQ的线程
找到进程IDNode.js 学习笔记_第18张图片

二、fs模块

file system 文件系统
Node.js 学习笔记_第19张图片

1. 写入文件

文件不存在会自动创建。
在这里插入图片描述

// 导入模块
const fs1 =require('fs');
// 写入文件
fs1.writeFile('./f_write.txt','abcdefg',err=>{
    if(err){
        console.log('写入失败')
        return;
    }
})

2.同步与异步

2.1 异步写入

// 导入模块
const fs1 =require('fs');
// 写入文件
fs1.writeFile('./f_write.txt','abcdefg',err=>{
    if(err){
        console.log('写入失败')
        return;
    }
    console.log('写入成功')
})
console.log('1')

上述代码有两个线程

  1. JS主线程——执行解析JS代码。

  2. 磁盘写入——输入/输出( I / O)线程

writeFile方法是异步的。

当上述I/O线程完成后,将回调函数(err)压入队列中,等主线程执行完后续代码后,再取出这个函数,执行。

效果展示

Node.js 学习笔记_第20张图片

2.2 同步写入

// 导入模块
const fs1 =require('fs');
// 写入文件
fs1.writeFileSync('./test1','test1');

写入效果:
在这里插入图片描述

3.文件的追加写入

3.1 appendFile

// 导入模块
const fs2 =require('fs');
// 写入文件
fs2.appendFile('./append.txt','append!!',err=>{
    //写入成功则返回错误对象,失败则返回none
    if(err){
        console.log('追加写入失败')
        return
    }
    console.log('追加写入成功')
})

在这里插入图片描述
在这里插入图片描述

3.2 appendFileSync

// 导入模块
const fs2 =require('fs');
// 写入文件
fs2.appendFileSync('./append.txt','\r\nappend!!')//进行换行操作

Node.js 学习笔记_第21张图片

3.3 writeFile…{flag:‘a’}

Node.js 学习笔记_第22张图片

// 导入模块
const fs1 =require('fs');
// 写入文件(第一遍直接写入的
// fs1.writeFile('./f_write.txt','ABC',err=>{
    //追加写法——添加配置项
fs1.writeFile('./f_write.txt','hhhh',{flag:'a'},err=>{
    if(err){
        console.log('写入失败')
        return;
    }
    console.log('写入成功')
})
console.log('1')

Node.js 学习笔记_第23张图片

4.文件流式写入

// 导入模块
const fs1 =require('fs');
//创建写入对象
const ws=fs1.createWriteStream('fff.txt');
//write
ws.write('乘醉听萧鼓\r\n')
ws.write('吟赏烟霞\r\n')
ws.write('异日图将好景\r\n')
ws.write('归去凤池夸\r\n')
//关闭通道
ws.close()

Node.js 学习笔记_第24张图片

5.文件读取

5.1 异步读取

// // 导入模块
const fs1 =require('fs');
// //创建写入对象
// const ws=fs1.createWriteStream('fff.txt');
// //write
// ws.write('乘醉听萧鼓\r\n')
// ws.write('吟赏烟霞\r\n')
// ws.write('异日图将好景\r\n')
// ws.write('归去凤池夸\r\n')
// //关闭通道
// ws.close()

//读取上面写入的文档,并进行输出
fs1.readFile('./fff.txt',(err,data)=>{
    if(err){
        console.log('读取失败')
        return
    }
    console.log(data)
    console.log(data.toString())
})

Node.js 学习笔记_第25张图片

5.2 同步读取

// // 导入模块
const fs1 =require('fs');
//读取
let data=fs1.readFileSync('./fff.txt')
console.log(data)
console.log(data.toString())

Node.js 学习笔记_第26张图片

5.3 流式读取

// // 导入模块
const fs1 =require('fs');
//流式读取
let rs=fs1.createReadStream('./fff.txt')
rs.on('data',data=>{
    console.log(data)
})
//读取完毕后,执行end回调
rs.on('end',()=>{
    console.log('读取完成')
})

7.文件重命名、移动

7.1 异步

// // 导入模块
const fs1 =require('fs');
//重命名
fs1.rename('./fff.txt','./poem.txt',err=>{
    if(err) throw err
    console.log('移动完成')
})

也可以用它来修改路径

Node.js 学习笔记_第27张图片

7.2 同步

// // 导入模块
const fs1 =require('fs');
//重命名
fs1.renameSync('./poem.txt','./poemAA.txt')

8.删除

以下两个方法均有同步方法

8.1 unlink方法

// // 导入模块
const fs1 =require('fs');
//删除
fs1.unlink('./poemAA.txt',err=>{
    if(err){
        console.log('删除失败')
        return
    }
    console.log('删除成功')
})

8.2 rm方法

// // 导入模块
const fs1 =require('fs');
//删除
fs1.rm('./f_write.txt',err=>{
    if(err){
        console.log('删除失败')
        return
    }
    console.log('删除成功')
})

在这里插入图片描述

9.文件夹操作

9.1 文件夹创建mkdir

make directory

// // 导入模块
const fs1 =require('fs');
//删除
fs1.mkdir('./html',err=>{
    if(err){
        console.log('创建失败');
        return
    }
    console.log('创建成功')
})
递归创建
// // 导入模块
const fs1 =require('fs');
//删除
fs1.mkdir('./a/b/c',err=>{
    if(err){
        console.log('创建失败');
        return
    }
    console.log('创建成功')
})
//D:\web>node test.js
//创建失败    

需要添加配置项

// // 导入模块
const fs1 =require('fs');
//删除
fs1.mkdir('./a/b/c',{recursive:true},err=>{
    if(err){
        console.log('创建失败');
        return
    }
    console.log('创建成功')
})

Node.js 学习笔记_第28张图片

9.2 文件夹读取readdir

// // 导入模块
const fs1 =require('fs');
//删除
fs1.readdir('./vue3',(err,data)=>{
    if(err){
        console.log('创建失败');
        return
    }
    console.log('创建成功',data)
})

Node.js 学习笔记_第29张图片

9.3 删除文件夹rmdir

rm——remove

系统建议使用rm来代替rmdir

(node:968) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead

// // 导入模块
const fs1 =require('fs');
//删除
fs1.rmdir('./html',err=>{
    if(err){
        console.log('删除失败')
        return
    }
    console.log('删除成功')
})

若删除之后再次运行,则显示删除失败

Node.js 学习笔记_第30张图片

递归删除
// // 导入模块
const fs1 =require('fs');
//想删除a文件夹下的所以目录
fs1.rmdir('./a',err=>{
    if(err){
        console.log('删除失败',err)
        return
    }
    console.log('删除成功')
})

Node.js 学习笔记_第31张图片

// 导入模块
const fs1 =require('fs');
//想删除a文件夹下的所以目录
fs1.rmdir('./a',{recursive:true},err=>{
    if(err){
        console.log('删除失败')
        return
    }
    console.log('删除成功')
})

10.查看资源状态

// 导入模块
const fs1 =require('fs');
//stat方法 status缩写
fs1.stat('./2023_1/demo/动态表格视频.mp4',(err,data)=>{
    if(err){
        console.log('操作失败')
        return
    }
    console.log('操作成功',data)
})

Node.js 学习笔记_第32张图片

  • size 文件体积
  • birthtime 创建时间
  • mtime 最后修改时间
  • atime 最后访问时间
  • ctime 最后修改文件状态时间
  • isFile 检测是否为文件
  • isDirectory 检测是否为文件夹

11.路径补充说明

Node.js 学习笔记_第33张图片

// // 导入模块
const fs1 =require('fs');
//使用绝对路径删除
fs1.rm('D:/web/test1',err=>{
    if(err){
        console.log('删除失败')
        return
    }
    console.log('删除成功')
})

D:/web/test1 最初的形式是D:\web\test1反斜杠,要改成 / 才可以进行操作

12.相对路径的bug解决

使用相对路径时的参照目录是命令行所在的目录,而不是当前文件的所在的所在目录。

__dirname 保存着 当前文件所在目录的绝对路径

13、path模块

Node.js 学习笔记_第34张图片

1. path.resolve

拼接规范的逻辑路径
console.log(__dirname+'/index.html')如下图所示 斜杠不一致
Node.js 学习笔记_第35张图片

console.log(__dirname+'/index.html')

2.其他

  1. console.log(path1.sep)
    在这里插入图片描述
  2. 文件的绝对路径console.log(__filename)
    Node.js 学习笔记_第36张图片
  3. 解析文件
let ts='D:\\web\\node\\test.js'
console.log(path1.parse(ts))

Node.js 学习笔记_第37张图片

  1. 获取文件名
let ts='D:\\web\\node\\test.js'
console.log(path1.basename(ts))

在这里插入图片描述

  1. 获取路径的目录名、扩展名
let ts='D:\\web\\node\\test.js'
console.log(path1.dirname(ts))
console.log(path1.extname(ts))```

在这里插入图片描述

14.URL补充

网页中的 URL 主要分为两大类:相对路径与绝对路径

绝对路径可靠性强,而且相对容易理解,在项目中运用较多

Node.js 学习笔记_第38张图片
相对路径
如果已经在最外层,再加…/还是不变,依旧是最外层
Node.js 学习笔记_第39张图片
使用场景
Node.js 学习笔记_第40张图片

三、http协议

hypertext Transfer Protocol
超文本传输协议
Node.js 学习笔记_第41张图片
请求报文,响应报文

1.http报文

Node.js 学习笔记_第42张图片

encode 编码 decode解码

1.1 请求报文结构

Node.js 学习笔记_第43张图片

(1) 请求行

Node.js 学习笔记_第44张图片

  • 请求方法
    Node.js 学习笔记_第45张图片

  • url
    Node.js 学习笔记_第46张图片
    用于定位服务器中资源
    在这里插入图片描述

端口号有些情况下可以省略

以百度为例Node.js 学习笔记_第47张图片> 主机名=域名?Node.js 学习笔记_第48张图片
http版本号
Node.js 学习笔记_第49张图片
Node.js 学习笔记_第50张图片

(2)请求头

以键值对形式存在。
https提高交互的安全性。
Node.js 学习笔记_第51张图片

(3)请求体

可以随意设置,与后端商量好在这里插入图片描述
json形式的请求体 在这里插入图片描述

1.2 响应报文

Node.js 学习笔记_第52张图片

(1)响应行

在这里插入图片描述

响应状态码
Node.js 学习笔记_第53张图片
Node.js 学习笔记_第54张图片

响应状态描述
Node.js 学习笔记_第55张图片

(2)响应头

记录了与服务器相关的东西
Node.js 学习笔记_第56张图片

(3)响应体

Node.js 学习笔记_第57张图片

2. 网络基础概念

2.1 IP

就像发件写 收件地址
IP——寻找网络设备
Node.js 学习笔记_第58张图片
将32位二进制转为10进制Node.js 学习笔记_第59张图片
作用
在这里插入图片描述
只要设备接入互联网,它都有自己的ip地址。

2.2 IP分类

Node.js 学习笔记_第60张图片

(1)局域网IP

解决IP不够用的方法:共享IPNode.js 学习笔记_第61张图片
Node.js 学习笔记_第62张图片

(2)广域网IP

连接互联网Node.js 学习笔记_第63张图片

局域网ip可以复用

(2)本地回环IP地址

在这里插入图片描述

2.1 端口

Node.js 学习笔记_第64张图片
作用在这里插入图片描述
Node.js 学习笔记_第65张图片


主战区转换为后端:服务器

四、http 模块

1. 创建HTTP服务端

// 导入模块
const http=require('http');

// 创建服务对象
// request,response是两个形参,分别是对请求,响应报文的封装
// 当服务接收到请求时,回调函数执行
const server=http.createServer((request,response)=>{
    // 设置响应体并结束响应体
    response.end('hello HTTP Server')
});

// 监听端口,启动服务器
// 当服务启动成功以后执行此回调函数
m /

在这里插入图片描述
浏览器向服务器发送请求
Node.js 学习笔记_第66张图片

注意事项Node.js 学习笔记_第67张图片
当响应体中有中文response.end('你好 HTTP')时,该怎么解决。在这里插入图片描述

// 导入模块
const http=require('http');

// 创建服务对象
// request,response是两个形参,分别是对请求,响应报文的封装
// 当服务接收到请求时,回调函数执行
const server=http.createServer((request,response)=>{
    // 设置响应体并结束响应体
    response.setHeader('content-type','text/html;charset=utf-8')
    response.end('你好 HTTP')
});

// 监听端口,启动服务器
// 当服务启动成功以后执行此回调函数
server.listen(9000,()=>{
    console.log('服务已经启动...')
});

在这里插入图片描述
若有端口被占用,则进入任务管理器或者资源监视器,结束任务。
Node.js 学习笔记_第68张图片

2. 在浏览器中查看报文

请求头
Node.js 学习笔记_第69张图片
Node.js 学习笔记_第70张图片
提交表单后

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="http://127.0.0.1:9000" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="submit" name="">
    </form>
</body>
</html>

Node.js 学习笔记_第71张图片
Node.js 学习笔记_第72张图片

3. 提取请求报文的内容

(1)获取请求头

const http=require('http');

// 当服务接收到请求时,回调函数执行
const server=http.createServer((request,response)=>{
    // 获取请求的方法
    console.log(request.method);
    // 获取请求的url(只包含路径与查询字符串)
    console.log(request.url)
    // 获取请求头
    console.log(request.headers)
    // 设置响应体并结束响应体
    response.setHeader('content-type','text/html;charset=utf-8')
    response.end('你好 HTTP')
});

// 监听端口,启动服务器
// 当服务启动成功以后执行此回调函数
server.listen(9000,()=>{
    console.log('服务已经启动...')
});

Node.js 学习笔记_第73张图片

(2) 获取请求体

提取路径和查询字符串

const http=require('http');

const server=http.createServer((request,response)=>{
    let url=new URL(request.url,'http://127.0.0.1')
    console.log(url)
    response.setHeader('content-type','text/html;charset=utf-8')
    response.end('请求成功')
});

server.listen(9000,()=>{
    console.log('服务已经启动...')
});


//请求体的内容
URL {
  href: 'http://127.0.0.1/search?key=123',
  origin: 'http://127.0.0.1',
  protocol: 'http:',
  username: '',
  password: '',
  host: '127.0.0.1',
  hostname: '127.0.0.1',
  port: '',
  pathname: '/search',
  search: '?key=123',
  searchParams: URLSearchParams { 'key' => '123' },
  hash: ''
}
URL {
  href: 'http://127.0.0.1/favicon.ico',
  origin: 'http://127.0.0.1',
  protocol: 'http:',
  username: '',
  password: '',
  host: '127.0.0.1',
  hostname: '127.0.0.1',
  port: '',
  pathname: '/favicon.ico',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}

Node.js 学习笔记_第74张图片

查询路径和字符串

    let url=new URL(request.url,'http://127.0.0.1')
    console.log('查询路径:',url.pathname)
    console.log('\n查询字符串:',url.searchParams)

在这里插入图片描述
取出字符串console.log(url.searchParams.get('key'))
在这里插入图片描述

(3)http请求练习

Node.js 学习笔记_第75张图片

const http=require('http');

// 创建服务
const server=http.createServer((request,response)=>{
    //获取请求的方法
    // let method =request.method
    // 简写:解构赋值
    let method =request.method
    //获取请求的路径
    let pathname =new URL(request.url,'http://127.0.0.1').pathname
    //设置响应头
    response.setHeader('content-type','text/html;charset=utf-8')
    
    //判断
    if(method === 'GET' && pathname === '/login'){
        response.end('登录页面')
    }else if(method === 'GET' && pathname === '/reg'){
        response.end('注册页面')
    }else{
        response.end('404')
    }
    //每次请求只能对应一次end方法
});

server.listen(9000,()=>{
    console.log('服务已经启动...\n端口9000监听中...')
});

pathname 是一个 URL 对象的属性,它并不是一个字符串。为了正确判断请求的路径,需要使用pathname.pathname 来获取路径字符串,然后进行比较。
注意路径别写成./login
Node.js 学习笔记_第76张图片
在这里插入图片描述
Node.js 学习笔记_第77张图片

4.设置响应报文

const http=require('http')
const server=http.createServer((request,response)=>{
    // 设置响应状态码
    response.statusCode=201;
    // 响应状态的描述,一般不用
    response.statusMessage='message'
    // 设置响应头,用来表示服务端的名字
    response.setHeader('ch','text/html;charset=utf-8')
    response.setHeader('Flavia','FFFFF')
    // 响应体,write方法与end方法相比,可多次调用
    response.write('love')
    response.write('\npatience')
    //每个请求必须有end方法,且只能有一个
    response.end()
})
server.listen(9000,()=>{
    console.log('服务已经启动...')
})

Node.js 学习笔记_第78张图片

(1)http响应练习

搭建 HTTP 服务,响应一个 4 行 3 列的表格,并且要求表格有 隔行换色效果 ,且 点击 单元格能 高亮显示


const http=require('http')
const server=http.createServer((request,response)=>{

    response.end(`
    


    
    
    Document
    


   
`
) }) server.listen(9000,()=>{ console.log('服务已经启动...') })

Node.js 学习笔记_第79张图片


const http=require('http')
const server=http.createServer((request,response)=>{

    response.end(`
    


    
    
    Document
    


   
`
) }) server.listen(9000,()=>{ console.log('服务已经启动...') })

Node.js 学习笔记_第80张图片

(2)优化

把html内容单独放一个文件


const http=require('http')
const fs=require('fs')
const server=http.createServer((request,response)=>{
    let html=fs.readFileSync(__dirname+'/index.html')
    response.end(html)
})
server.listen(9000,()=>{
    console.log('服务已经启动...')
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        td{
            padding:10px 35px;
        }
        table,td{
            border-collapse:collapse;
        }
        table tr:nth-child(odd){
            background: #eee;
        }
        table tr:nth-child(even){
            background: #fff;
        }
    </style>
</head>
<body>
   <table border=1>
    <tr><td></td><td></td><td></td></tr>
    <tr><td></td><td></td><td></td></tr>
    <tr><td></td><td></td><td></td></tr>
    <tr><td></td><td></td><td></td></tr>
   </table>
   <script>
    //获取所有td
    let tds=document.querySelectorAll('td')
    //遍历
    tds.forEach(item=>{
        item.onmouseover=function(){
            this.style.background='#ccc'
        }
        item.onmouseout=function(){
            this.style.background='#fff'
        }
    })
   </script>
</body>
</html>

(3)实现引入外部文件

想要独立css,js文件
根据请求路径区分请求结果,而不是每个文件都是html形式。尚硅谷第56集

Node.js 学习笔记_第81张图片

5. 网页资源加载的基本过程

这两个请求关系不大
在这里插入图片描述
很多请求都是并行的。
Node.js 学习笔记_第82张图片
执行着,遇到了,就去请求

6.静态资源,动态资源

静态资源:内容长时间不发生改变的资源
动态资源:内容经常更新的资源
Node.js 学习笔记_第83张图片

7.搭建静态资源服务

需求
Node.js 学习笔记_第84张图片


const http=require('http')
const fs=require('fs')
const server=http.createServer((request,response)=>{
    // 请求url路径
    let {pathname}=new URL(request.url,'http://127.0.0.1');
    // 拼接文件路径
    let filePath=__dirname+pathname;
    fs.readFile(filePath,(err,data)=>{
        if(err){
            response.statusCode=500;
            response.end('文件读取失败');
            return;
        }
        response.setHeader('content-type','text/html;charset=utf-8')
        response.end(data)
    })
})
server.listen(9000,()=>{
    console.log('服务已经启动...')
});

(1)静态资源目录(网站根目录)

HTTP 服务在哪个文件夹中寻找静态资源,那个文件夹就是 静态资源目录 ,也称之为 网站根目录

8.设置mime类型

媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。

mime 类型结构: [type]/[subType]
例如: text/html text/css image/jpeg image/png application/json

HTTP 服务可以设置响应头 Content-Type 来表明响应体的 MIME 类型,浏览器会根据该类型决定如何处理资源.

//是常见文件对应的 mime 类型
html: 'text/html',
css: 'text/css',
js: 'text/javascript',
png: 'image/png',
jpg: 'image/jpeg',
gif: 'image/gif',
mp4: 'video/mp4',
mp3: 'audio/mpeg',
json: 'application/json'

对于未知的资源类型,可以选择 application/octet-stream 类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的 下载 效果

9.解决乱码问题

响应头的优先级更高
Node.js 学习笔记_第85张图片
如果是html格式,则加上utf-8

10.完善错误处理

Node.js 学习笔记_第86张图片
在这里插入图片描述

11.GET和POST请求场景

Node.js 学习笔记_第87张图片

GET和POST请求的区别

  • GET 和 POST 是 HTTP 协议请求的两种方式。
  • GET 主要用来获取数据,POST 主要用来提交数据(上面两点两者都可以)
  • GET 带参数请求是将参数缀到 URL 之后,在地址栏中输入 url 访问网站就是 GET 请求,
  • POST 带参数请求是将参数放到请求体中

五、模块化

1.介绍

  • 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化。
  • 其中拆分出的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用。

好处:
  1. 防止命名冲突
  2. 高复用性
  3. 高维护性

2.暴露数据

D:\web\node\fn.js

function tie(){
    console.log('贴膜...')
}
//暴露数据
module.exports=tie
D:\web\node\index.js

// 导入模块
const tie =require('./fn.js')
//调用函数
tie()

在这里插入图片描述

3.暴露方式

注意:

  • module.exports 可以暴露 任意 数据
  • 不能使用 exports = value 的形式暴露数据,模块内部 module 与 exports 的隐式关系
    exports = module.exports = {} ,require 返回的是目标模块中 module.exports 的值

(1)module.exports = value

Node.js 学习笔记_第88张图片

在这里插入图片描述

(2)exports.name = value

Node.js 学习笔记_第89张图片

此处的代码改变则不生效

exports.tie=tie
exports.hi=hi

在这里插入图片描述


![在这里插入图片描述](https://img-blog.csdnimg.cn/50a1a2345eaf4fbfa7d47d227a7254aa.png)
console.log(module.exports===exports)

在这里插入图片描述

4.导入模块

使用require函数

  1. 对于自己创建的模块,导入时路径建议写 相对路径 ,且不能省略 ./../
  2. js 和 json 文件导入时可以不用写后缀,如果js和json名字一样,则先检测js,c/c++编写的 node 扩展文件也可以不写后缀,但是一般用不到
  3. 如果导入其他类型的文件,会以 js 文件进行处理
  4. 如果导入的路径是个文件夹,则会 首先 检测该文件夹下 package.json 文件中 main 属性对应
    的文件,如果存在则导入,反之如果文件不存在会报错。
    如果 main 属性不存在,或者 package.json 不存在,则会尝试导入文件夹下的 index.js 和index.json ,
    如果还是没找到,就会报错
  5. 导入 node.js 内置模块时,直接 require 模块的名字即可,无需加 ./ 和 …/

Node.js 学习笔记_第90张图片
没有反应??

5.导入自定义模块的基本流程

  1. 将相对路径转为绝对路径,定位目标文件
  2. 缓存检测
  3. 读取目标文件代码
  4. 包裹为一个函数并执行(自执行函数)。通过 arguments.callee.toString() 查看自执行函数
  5. 缓存模块的值
  6. 返回 module.exports 的值
    Node.js 学习笔记_第91张图片
    Node.js 学习笔记_第92张图片
// 伪代码
function require(){
    // 转换为绝对路径
    let absolutePath=path.resolve(__dirname,file);
    // 缓存检测
    if(caches[absolutePath]){
        return caches[absolutePath]
    }
    //读取文件内容
    let code=fs.readFileSync(absolutePath).toString()
    
    // 包裹成函数,执行
    let module={}
    let exports=module.exports={}
    function (exports, require, module, __filename, __dirname) {
        const test={
            name:'尚硅谷'
        }
        module.exports=test;
        // 输出指向函数的代码体
        console.log(arguments.callee.toString())
        }(exports, require, module, __filename, __dirname)
        //缓存
        caches[absolutePath]=module.exports
    }
const m=require('./fn.js')

因为缓存,只执行一次

在这里插入图片描述

module.exports 、 exports 以及 require 这些都是 CommonJS 模块化规范中的内容。
而 Node.js 是实现了 CommonJS 模块化规范,二者关系有点像 JavaScript 与 ECMAScript

六、包管理工具

  • 『包』英文单词是 package ,代表了一组特定功能的源码集合
  • 包管理工具——管理『包』的应用软件,可以对「包」进行 下载安装 , 更新 , 删除 , 上传 等操作
  • 借助包管理工具,可以快速开发项目,提升开发效率
  • 包管理工具是一个通用的概念,很多编程语言都有包管理工具,所以 掌握好包管理工具非常重要

常用的包管理工具 npm yarn cnpm

1.npm

npm 全称 Node Package Manager ,翻译为中文意思是『Node 的包管理工具』
npm 是 node.js 官方内置的包管理工具,是 必须要掌握住的工具.

2. 初始化

创建一个空目录,然后以此目录作为工作目录 启动命令行工具 ,执行 npm init

终端显示如下

D:\web\node\files1>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.      

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (files1) npm1
version: (1.0.0)                                                                 
description:                                                                     
entry point: (index.js)                                                          
test command:                                                                    
git repository:                                                                  
keywords:                                                                        
author: F                                                                        
license: (ISC)                                                                   
About to write to D:\web\node\files1\package.json:

{
  "name": "npm1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "F",
  "license": "ISC"
}

确认最后一步之后,自动创建一个json文件。

npm init 命令的作用是将文件夹初始化为一个『包』, 交互式创建 package.json 文件 package.json
是包的配置文件,每个包都必须要有 package.json

Node.js 学习笔记_第93张图片
初始化过程中的注意事项:

  1. package name ( 包名 ) 不能使用中文、大写,默认值是 文件夹的名称 ,所以文件夹名称也不能使用中文和大写
  2. version ( 版本号 )要求 x.x.x 的形式定义, x 必须是数字,默认值是 1.0.0
  3. ISC 证书与 MIT 证书功能上是相同的,关于开源证书扩展阅读http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html
  4. package.json 可以手动创建与修改
  5. 使用 npm init -y 或者 npm init --yes 极速创建 package.json
    Node.js 学习笔记_第94张图片

3.npm搜索,下载,使用包

(1)搜索(search)

  1. 命令行 npm s
  2. 网站搜索网址 https://www.npmjs.com/

(2)下载(install)

  1. 通过 npm installnpm i 命令安装包
# 示例
npm install uniq
npm i uniq

安装后的目录如下
Node.js 学习笔记_第95张图片

  • 运行之后文件夹下会增加两个资源node_modules 文件夹 存放下载的包
  • package-lock.json 包的锁文件 ,用来锁定包的版本

安装 uniq 之后, uniq 就是当前这个包的一个 依赖包 ,有时会简称为 依赖

比如我们创建一个包名字为 A,A 中安装了包名字是 B,我们就说 B 是 A 的一个依赖包 ,也会说A 依赖 B

(3)使用

// 导入uniq包
const uniq=require('uniq')
// 使用
let arr=[1,1,5,4,2,2,2,2,2,3,1]
const result =uniq(arr)
console.log(arr)
console.log(result)

在这里插入图片描述
由结果可见,此方法会改变原数组,并且结果经排序后输出。

4. require导入包

Node.js 学习笔记_第96张图片

以下代码等价

但是第一种写法const uniq=require('uniq')更灵活就,因为:如果node_modules文件夹安装在了外层目录,根据如下规则:

  1. 在当前文件夹下 node_modules 中寻找同名的文件夹
  2. 在上级目录中下的 node_modules 中寻找同名的文件夹,直至找到磁盘根目录
    还是能成功导入模块

在这里插入图片描述

5.开发与生产依赖

举个例子方便大家理解,比如说做蛋炒饭需要 大米 , 油 , 葱 , 鸡蛋 , 锅 , 煤气 , 铲子 等
其中 锅 , 煤气 , 铲子 属于开发依赖,只在制作阶段使用
大米 , 油 , 葱 , 鸡蛋 属于生产依赖,在制作与最终食用都会用到
所以 开发依赖 是只在开发阶段使用的依赖包,而 生产依赖 是开发阶段和最终上线运行阶段都用到的依赖包

(1) 生产环境与开发环境

  • 开发环境是程序员 专门用来写代码 的环境,一般是指程序员的电脑,开发环境的项目一般 只能程序员自己访问
  • 生产环境是项目 代码正式运行 的环境,一般是指正式的服务器电脑,生产环境的项目一般 每个客户都可以访问

(2)生产依赖

运行时也使用它

生产依赖 npm i -S uniq或者npm i --save uniq
-S 等效于 --save, -S 是默认选项
包信息保存在 package.json 中 dependencies 属性

(3)开发依赖

只在开发阶段使用
npm i -D less
npm i --save-dev less
-D 等效于 --save-dev
包信息保存在 package.json 中 devDependencies 属性

npm i --save uniq
npm i -D less

Node.js 学习笔记_第97张图片

在这里插入图片描述
在这里插入图片描述

6.全局安装 -g

执行安装选项 -g 进行全局安装
全局安装完成之后就可以在命令行的任何位置运行 nodemon 命令
该命令的作用是 自动重启 node 应用程序

npm i -g nodemon

在这里插入图片描述

// 导入模块
const http=require('http');

// 创建服务对象
const server=http.createServer((request,response)=>{
    response.setHeader('content-type','text/html;charset=utf-8')
    response.end('你好 nodemon')
});

// 监听端口,启动服务器
// 当服务启动成功以后执行此回调函数
server.listen(9000,()=>{
    console.log('服务已经启动...')
});

当返回的内容改变时,不需要手动重启服务器,使用nodemon会自动重启,只需要在浏览器界面刷新即可
Node.js 学习笔记_第98张图片

Node.js 学习笔记_第99张图片

实时根据内容的改变,自动重启服务器
Node.js 学习笔记_第100张图片
Node.js 学习笔记_第101张图片

说明:

  • 全局安装的命令不受工作目录位置影响
  • 可以通过 npm root -g 可以查看全局安装包的位置
  • 不是所有的包都适合全局安装 , 只有全局类的工具才适合,可以通过 查看包的官方文档来确定安装方式 ,这里先不必太纠结

在这里插入图片描述

7.修改window执行策略

目的:为解决 全局包无法使用的问题

如果可以使用nodemon命令,则不用管这些

  • 方法一
    Node.js 学习笔记_第102张图片
  • 方法二
    修改vscode的终端窗口
    Node.js 学习笔记_第103张图片

8.环境变量Path

在这里插入图片描述

Node.js 学习笔记_第104张图片

Node.js 学习笔记_第105张图片
当输入QQ命令时,会在当前目录查找以exe或者cmd结尾的文件,找不到则无法运行。

目的:不论在哪个目录都可以通过命令行找到QQ

步骤

  1. 把QQ所在目录复制D:\Tencent\QQ\Bin
  2. 打开高级设置——环境变量Node.js 学习笔记_第106张图片
  3. 打开用户变量中的PathNode.js 学习笔记_第107张图片
    4.重新打开一个命令行
    Node.js 学习笔记_第108张图片

Path 是操作系统的一个环境变量,可以设置一些文件夹的路径,在当前工作目录下找不到可执行文件时,就会在环境变量 Path 的目录中挨个的查找,如果找到则执行,如果没有找到就会报错

9.安装包的所有依赖

在项目协作中有一个常用的命令就是 npm i通过该命令可以依据 package.jsonpackag-lock.json 的依赖声明安装项目依赖
node_modules 文件夹
。大多数情况都不会存入版本库

作用:下载 这个包(项目)安装的所有依赖。一般用于拉取远程仓库的代码,之后执行的。或者把文件发给别人,不用打包node_modules文件夹,人家npm i即可。

10.安装指定版本、删除包

项目中可能会遇到版本不匹配的情况,有时就需要安装指定版本的包

  1. 安装指定版本包
## 格式
npm i <包名@版本号>
## 示例
npm i jquery@1.11.2

Node.js 学习笔记_第109张图片
Node.js 学习笔记_第110张图片
2. 删除包
在这里插入图片描述
Node.js 学习笔记_第111张图片

11.配置命令别名

  1. 点开package.json
  2. 找到script属性Node.js 学习笔记_第112张图片
  3. 配置别名Node.js 学习笔记_第113张图片
  4. 执行
//index.中的内容
console.log('hi')

Node.js 学习笔记_第114张图片

start 别名比较特别,使用时可以省略 run

"scripts": {
"start": "node index.js"
},

Node.js 学习笔记_第115张图片

npm start 是项目中常用的一个命令,一般用来启动项目 npm run 有自动向上级目录查找的特性,跟 require 函数也一样
对于陌生的项目,我们可以通过查看 scripts 属性来参考项目的一些操作

12.cnpm

  • cnpm 是一个淘宝构建的 npmjs.com 的完整镜像,也称为『淘宝镜像』,网址https://npmmirror.com/
  • cnpm 服务部署在国内 阿里云服务器上 , 可以提高包的下载速度
  • 官方也提供了一个全局工具包 cnpm ,操作命令与 npm 大体相同

(1)安装

npm install -g cnpm --registry=https://registry.npmmirror.com

Node.js 学习笔记_第116张图片

(2)操作命令

初始化Node.js 学习笔记_第117张图片

功能 命令
初始化 cnpm init / cnpm init
安装包 cnpm i uniq
安装包 cnpm i -S uniq
安装包 cnpm i -D uniq
安装包 cnpm i -g nodemon
安装项目依赖 cnpm i
删除 cnpm r uniq

Node.js 学习笔记_第118张图片

(3)配置淘宝镜像

用 npm 也可以使用淘宝镜像,配置的方式有两种

  • 直接配置
npm config set registry https://registry.npmmirror.com/
  • 工具配置
    使用 nrm 配置 npm 的镜像地址 npm registry manager(nrm作用:决定npm到哪去下载包)
    Node.js 学习笔记_第119张图片
    1. 安装 nrm npm i -g nrm
    2. 修改镜像 nrm use taobao
    3. 检查是否配置成功(选做) npm config list
    4. 检查 registry 地址是否为https://registry.npmmirror.com/ , 如果 是 则表明成功Node.js 学习笔记_第120张图片

补充说明:
建议使用第二种方式 进行镜像配置,因为后续修改起来会比较方便
还可以使用nrm use npm切换回原来的

Node.js 学习笔记_第121张图片

13.yarn

yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方网址:https://yarnpkg.com/

yarn 官方宣称的一些特点

  • 速度超快:yarn 缓存了每个下载过的包,所以再次使用时无需重复下载。 同时利用并行下载以最大
  • 化资源利用率,因此安装速度更快
  • 超级安全:在执行代码之前,yarn 会通过算法校验每个安装包的完整性
  • 超级可靠:使用详细、简洁的锁文件格式和明确的安装算法,yarn 能够保证在不同系统上无差异的
    工作

(1)安装

使用 npm 安装 yarn

npm i -g yarn

Node.js 学习笔记_第122张图片

(2)命令操作

功能 命令
初始化 yarn init 或 yarn init -y
安装包 yarn add uniq (生产依赖)
安装包 yarn add less --dev (开发依赖)
安装包 yarn global add nodemon (全局安装)
删除包 yarn remove uniq (删除项目依赖包)
删除包 yarn global remove nodemon (全局删除包)
安装项目依赖 yarn
运行命令别名 yarn <别名> (不需要添加 run)

Node.js 学习笔记_第123张图片

{
  "dependencies": {
    "uniq": "^1.0.1"
  },
  "name": "yarnf",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "node index.js"
  }
}

在这里插入图片描述

(3)全局安装中的注意点

因为没有配置环境变量,所以,通过yarn安装的-g等命令,没有作用,必须要配置环境变量。

  1. 找到yarn的位置
    在这里插入图片描述
    D:\nodejs\node_global\bin
  2. 手动配置环境变量

(4)配置淘宝镜像

可以通过如下命令配置淘宝镜像yarn config set registry https://registry.npmmirror.com/

Node.js 学习笔记_第124张图片

可以通过 yarn config list 查看 yarn 的配置项

14. npm 和 yarn 选择

根据不同的场景进行选择

  1. 个人项目
    如果是个人项目, 哪个工具都可以 ,可以根据自己的喜好来选择
  2. 公司项目
    如果是公司要根据项目代码来选择,可以 通过锁文件判断 项目的包管理工具
    npm 的锁文件为 package-lock.json
    yarn 的锁文件为 yarn.lock

包管理工具 不要混着用,切记,切记,切记

15.发布包

(1) 创建与发布

我们可以将自己开发的工具包发布到 npm 服务上,方便自己和其他开发者使用,操作步骤如下:

  1. 创建文件夹,并创建文件 index.js, 在文件中声明函数,使用 module.exports 暴露

  2. npm 初始化工具包,package.json 填写包的信息 (包的名字是唯一的)

  3. 注册账号 https://www.npmjs.com/signup

  4. 激活账号 ( 一定要激活账号 )

  5. 修改为官方的官方镜像 (命令行中运行 nrm use npm )在这里插入图片描述

  6. 命令行下 npm login 填写相关用户信息

  7. 命令行下 npm publish 提交包 在这里插入图片描述

+表示发布成功

可以进行安装和使用了
Node.js 学习笔记_第125张图片

(2) 更新包

后续可以对自己发布的包进行更新,操作步骤如下

  1. 更新包中的代码
    Node.js 学习笔记_第126张图片

  2. 测试代码是否可用Node.js 学习笔记_第127张图片

  3. 修改 package.json 中的版本号Node.js 学习笔记_第128张图片

  4. 运行npm publish 发布更新的版本

(3)删除包

执行如下命令删除包npm unpublish --force

**加粗样式**

减号表示删除成功

删除包需要满足一定的条件,
https://docs.npmjs.com/policies/unpublish

  • 你是包的作者
  • 发布小于 24 小时
  • 大于 24 小时后,没有其他包依赖,并且每周小于 300 下载量,并且只有一个维护者

16.包管理工具扩展介绍

在很多语言中都有包管理工具,比如:

语言 包管理工具
PHP composer
Python pip
Java maven
Go go mod
JavaScript npm/yarn/cnpm/other
Ruby rubyGems

除了编程语言领域有包管理工具之外,操作系统层面也存在包管理工具,不过这个包指的是『 软件包 』

操作系统 包管理工具 网址
Centos yum https://packages.debian.org/stable/
Ubuntu apt https://packages.ubuntu.com/
MacOS homebrew https://brew.sh/
Windows chocolatey https://chocolatey.org/

17.nvm的介绍与使用

全称:Node Version Manager ——用来管理node版本的工具,方便切换不同版本的node.js。

(1)下载安装

首先先下载 nvm,下载地址 https://github.com/coreybutler/nvm-windows/releases,
选择 nvm-setup.exe 下载即可(网络异常的小朋友可以在资料文件夹中获取)。

(2)常用命令

命令 说明
nvm list 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 删除某个版本的 Node.js
nvm use 18.12.1 切换 18.12.1 的 Node.js

Node.js 学习笔记_第129张图片

七、express框架

express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架,官方网址:https://www.expressjs.com.cn/
简单来说,express 是一个封装好的工具包,封装了很多功能,便于我们开发 WEB 应用(HTTP 服务)

1.初体验

(1)express下载

express 本身是一个 npm 包,所以可以通过 npm 安装

npm init
npm i express

在这里插入图片描述

(2)创建代码

创建 JS 文件,键入如下代码

// 导入express 
const express=require('express');
// 创建应用对象
const app=express();
// 创建路由
// 当浏览器发送请求的方法是get,且请求的路径是/home的话
// 就会执行后面的回调函数,为浏览器响应结果
app.get('/home',(req,res)=>{;
    // req是请求报文的封装对象,res是响应报文的封装对象。
    res.end('hi express');
})
// 监听端口,启动服务
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第130张图片
使用nodemon开启服务器。
Node.js 学习笔记_第131张图片
当正确输入路径后
Node.js 学习笔记_第132张图片

2.路由的使用

官方定义:路由确定了应用程序如何响应客户端对特定端点的请求

(1)路由的组成

一个路由的组成有 请求方法 , 路径 和 回调函数 组成
express 中提供了一系列方法,可以很方便的使用路由,使用格式:app.(path,callback)

app.get('/',(req,res)=>{;
    // req是请求报文的封装对象,res是响应报文的封装对象。
    res.end('home');
})

Node.js 学习笔记_第133张图片

(2)post请求

在地址栏回车键入的是get请求。所以无法获取login页面。

app.post('/login',(req,res)=>{
    res.end('login_post')
})

Node.js 学习笔记_第134张图片
解决方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
   <form method="post" action="http://127.0.0.1:3000/login">
    <button>发送</button>
   </form>
</body>
</html>

点击“发送”按钮,即可跳转到login页面

Node.js 学习笔记_第135张图片

(3)允许所有的请求方法

//js文件
const express=require('express');
const app=express();
app.all('/test',(req,res)=>{
    res.end('test_all')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})
//html文件
<body>
   <form method="post" action="http://127.0.0.1:3000/test">
    <button>发送</button>
   </form>
</body>

使用app.all( )这样不论是html文件的表单发送的get请求,还是通过网址栏发送的get请求,都能得到服务器返回的页面。

const express=require('express');
const app=express();
// 匹配所有方法
app.all('/test',(req,res)=>{
    res.end('test_all')
})
// 匹配404
app.all('*',(req,res)=>{
    // *表示匹配所有的路径
    res.end('404 Not Found')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})


Node.js 学习笔记_第136张图片

3.提取请求数据

(1)req属性

const express=require('express');
const app=express();
app.get('/request',(req,res)=>{
    // 原生操作
   console.log(req.method)
   console.log(req.url)
   console.log(req.httpVersion)
   console.log(req.headers)
   console.log('______________________________________')
   //express 操作
    console.log(req.path)
    console.log(req.query)
    console.log(req.ip)
   res.end('hello expression')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

输出结果

GET
/request?a=100&b=200
1.1
{
  host: '127.0.0.1:3000',
  connection: 'keep-alive',
  'cache-control': 'max-age=0',
  'sec-ch-ua': '"Microsoft Edge";v="117", "Not;A=Brand";v="8", "Chromium";v="117"',
  'sec-ch-ua-mobile': '?0',
  'sec-ch-ua-platform': '"Windows"',
  'upgrade-insecure-requests': '1',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.36',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
  'sec-fetch-site': 'none',
  'sec-fetch-mode': 'navigate',
  'sec-fetch-user': '?1',
  'sec-fetch-dest': 'document',
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
  cookie: '_ga=GA1.1.1922259483.1687846523; _ga_R1FN4KJKJH=GS1.1.1688639930.11.1.1688640103.0.0.0'
}
______________________________________
/request
{ a: '100', b: '200' }
::ffff:127.0.0.1

(2)req方法

const express=require('express');
const app=express();
app.get('/request',(req,res)=>{
    //express 方法
    // 获取请求头
    // console.log(req.get())
    // 只获取host请求头
    console.log(req.get('host'))
   res.end('hello expression')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

输出结果
//      127.0.0.1:3000

4. 获取路由参数

路由参数指的是 URL 路径中的参数(数据

(1)占位符 :f

const express=require('express');
const app=express();
app.get('/:idf.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    res.end('商品详情')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

使用:id占位符。

弹幕:商品页面就是固定的,然后去根据id请求数据库中的内容,渲染到当前页面

(2)获取路由参数req.params.f

通过req.params.idf得到请求数据时的路由参数。

const express=require('express');
const app=express();
app.get('/:idf.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    console.log(req.params.idf)
    res.end('商品详情')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})


Node.js 学习笔记_第137张图片
Node.js 学习笔记_第138张图片

在这里插入图片描述
Node.js 学习笔记_第139张图片

Node.js 学习笔记_第140张图片

(3)练习

为什么singers不能换成别的值
在这里插入图片描述

a.获取数据

下面两块代码只有占位符不同

const express=require('express');
//导入json文件
// 因为这个json文件里面有两层对象,所以使用解构赋值
const {singers}=require('./singers.json')
console.log(singers)
const app=express();
app.get('/single/:f.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    let{f}=req.params;
    res.end('商品详情')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})


最后结果变成数组。Node.js 学习笔记_第141张图片

const express=require('express');
//导入json文件
// 因为这个json文件里面有两层对象,所以使用解构赋值
const {singers}=require('./singers.json')
// console.log(singers)
const app=express();
app.get('/singer/:id.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    let{id}=req.params;
    // 在数组中寻找对应id的数据
    let result=singers.find(item=>{
        if(item.id===Number(id)){
            return true;
        }
    });
    console.log(result)
    res.end('result')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})
const express=require('express');
//导入json文件
// 因为这个json文件里面有两层对象,所以使用解构赋值
const {singers}=require('./singers.json')
// console.log(singers)
const app=express();
app.get('/singer/:f.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    let{f}=req.params;
    // 在数组中寻找对应id的数据
    let result=singers.find(item=>{
        if(item.id===Number(f)){
            return true;
        }
    });
    console.log(result)
    res.end('result')
})

app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})


item就是数组中的某个对象
Node.js 学习笔记_第142张图片

b.将数据展示到页面
const express=require('express');
//导入json文件
// 因为这个json文件里面有两层对象,所以使用解构赋值
const {singers}=require('./singers.json')
// console.log(singers)
const app=express();
app.get('/singer/:f.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    let{f}=req.params;
    // 在数组中寻找对应id的数据
    let result=singers.find(item=>{
        if(item.id===Number(f)){
            return true;
        }
    });
    // console.log(result)
    //当请求的内容不在json数据里,就返回404
    if(!result){
        res.statusCode=404;
        res.end(`

404 Not Found

`
) return; } res.end(` Document

${result.singer_name}

`
) }) app.listen(3000,()=>{ console.log('服务已经启动,端口3000正在监听中...') })

Node.js 学习笔记_第143张图片
Node.js 学习笔记_第144张图片
Node.js 学习笔记_第145张图片

5.响应设置

(1)原生响应

const express=require('express');
const app=express();
app.get('/response',(req,res)=>{
    // 原生响应
    res.statusCode=404
    res.statusMessage='love ping'
    res.setHeader('xxx','yyy')
    res.write('hello')

    res.end('response')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第146张图片

(2)内置响应

分开写

const express=require('express');
const app=express();
app.get('/response',(req,res)=>{
    res.status(500)
    res.set('chang','ping')
    res.send('你好')
    res.end('response')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

连着写

const express=require('express');
const app=express();
app.get('/response',(req,res)=>{
    res.status(500).set('haiying','changping').send('这很OK')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第147张图片

res.send('你好')方法会自动在响应头添加,防止中文展示乱码。Node.js 学习笔记_第148张图片

(3)其他响应

a.重定向
const express=require('express');
const app=express();
app.get('/other',(req,res)=>{
    //跳转响应
    res.redirect('https://mp.csdn.net/mp_blog/manage/article?spm=1000.2115.3001.5448')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第149张图片

b.下载

在网址输入路径后,自动下载软件

const express=require('express');
const app=express();
app.get('/other',(req,res)=>{
    //下载响应
    res.download(__dirname+'/package.json')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第150张图片

c.JSON响应
const express=require('express');
const app=express();
app.get('/other',(req,res)=>{
    //JSON响应
    res.json({
        'fang':'haiying',
        'age':'19'
    })
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第151张图片

d.响应文件内容
const express=require('express');
const app=express();
app.get('/other',(req,res)=>{
    // 响应文件内容
    res.sendFile(__dirname+'/index.html')
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
  <div style="color: pink;">你好呀</div>
</body>
</html>

Node.js 学习笔记_第152张图片

6.中间件

  1. 什么是中间件
    • 中间件(Middleware)本质是一个回调函数
    • 中间件函数 可以像路由回调一样访问 请求对象(request) , 响应对象(response)
  2. 中间件的作用
    中间件的作用 就是 使用函数封装公共操作,简化代码
  3. 中间件的类型
    全局中间件
    路由中间件

Node.js 学习笔记_第153张图片

(1)全局中间件

需求:记录每个请求的url和IP地址

a. 原始方法
const express=require('express');
const fs=require('fs')
const path=require('path')
const app=express();
app.get('/home',(req,res)=>{ 
    // 获取url和ip
     let {url,ip}=req;
     console.log(url+'   '+ip)
     //将信息保存在文件中
    fs.appendFileSync(path.resolve(__dirname,'./fhy.log'),`${url}${ip}\r\n`)
    res.send('主页')
})
app.get('/admin',(req,res)=>{
    res.send('后台')
})
app.all('*',(req,res)=>{
    res.send(`404 Not Found`)
})
app.listen(3000,()=>{
    console.log('服务已经启动,端口3000正在监听中...')
})

在这里插入图片描述
但是目前只对主页一个路径起作用

b.中间件方法

整个效果就是先执行中间件函数,然后通过next执行路由函数。

const express = require('express');
const fs = require('fs')
const path = require('path')
const app = express();

// 声明中间件函数
//next是内部函数,后续会指向路由或者中间件
function recordMiddleware(req, res, next) {
    // 获取url和ip
    let { url, ip } = req;
    console.log(url + '   ' + ip)
    //将信息保存在文件中
    fs.appendFileSync(path.resolve(__dirname, './fhy.log'), `${url}${ip}\r\n`)
    // 调用next函数
    next()
}

//使用中间件函数
app.use(recordMiddleware)

app.get('/home', (req, res) => {
    res.send('主页')
})
app.get('/admin', (req, res) => {
    res.send('后台')
})
app.all('*', (req, res) => {
    res.send(`404 Not Found`)
})
app.listen(3000, () => {
    console.log('服务已经启动,端口3000正在监听中...')
})

Node.js 学习笔记_第154张图片

Node.js 学习笔记_第155张图片

在这里插入图片描述
文件内容
在这里插入图片描述

(2)路由中间件——不是很懂

如果 只需要对某一些路由进行功能封装 ,则就需要路由中间件。

需求:在这里插入图片描述

const express = require('express');
const fs = require('fs')
const path = require('path')
const app = express();

// 声明中间件函数
//next是内部函数,后续会指向路由或者中间件
let checkCodeMid=(req, res, next)=> {
//    判断url的code参数是否等于521
    if(req.query.code==='521'){
        next()
    }else{
        res.send('暗号错误')
    }
    // 调用next函数
    next()
}

//使用中间件函数
app.use(checkCodeMid)

// 以下都是路由回调
app.get('/home', (req, res) => {
    res.send('主页')
})

//把中间件函数放到受约束的函数中
app.get('/admin', checkCodeMid,(req, res) => {
    res.send('后台')
})
app.get('/set',checkCodeMid, (req, res) => {
    res.send('设置页面')
})
app.all('*', (req, res) => {
    res.send(`404 Not Found`)
})
app.listen(3000, () => {
    console.log('服务已经启动,端口3000正在监听中...')
})

(3)静态资源中间件

静态资源目录(网站根目录)
浏览器发送给服务端请求后,服务端到哪个目录下去找对应的文化,则那个文件的文件夹就是静态资源目录。

const express = require('express');
const app = express();
//静态资源中间件的设置,将当前文件夹下的public目录作为网站的根目录
//express.static的返回结果是中间件函数
app.use(express.static(__dirname + '/public')); // 这个参数就是静态资源文件夹的路径

app.get('/home',(req,res)=>{
res.send('首页');
});

app.listen(3000,()=>{
console.log('3000 端口启动....');
});

public要放在init文件夹下面
Node.js 学习笔记_第156张图片

Node.js 学习笔记_第157张图片
Node.js 学习笔记_第158张图片

a.注意事项
  1. index.html 文件为默认打开的资源(即不输入/index.html,界面默认显示此文件)在这里插入图片描述
    Node.js 学习笔记_第159张图片

  2. 如果静态资源与路由规则同时匹配,谁先匹配谁就响应。

  3. 路由一般响应动态资源,静态资源中间件响应静态资源

b.练习

目的:使手机也可以通过局域网看到静态资源

Node.js 学习笔记_第160张图片
接下来是手机显示
Node.js 学习笔记_第161张图片
Node.js 学习笔记_第162张图片

7.获取请求体数据

使用 body-parser 包处理请求体
Node.js 学习笔记_第163张图片

需求如下:
在这里插入图片描述
通过按钮发送post请求数据,获取请求体
Node.js 学习笔记_第164张图片
Node.js 学习笔记_第165张图片

在npm搜索包,并选择路由中间件的使用方式

// create application/json parser
var jsonParser = bodyParser.json()

// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })

当中间件函数执行完毕后,会向req对象上,添加一个body属性。
Node.js 学习笔记_第166张图片

const express =require('express');
const app=express();
//导入解析请求体的包
const bodyParser=require('body-parser')
//解析queryString格式 请求体的中间件
const urlEncodeParser=bodyParser.urlencoded({extended:false})
//创建路由规则
app.get('/login',(req,res)=>{
    // 响应文件内容
    res.sendFile(__dirname+'/form.html')
})
app.post('/login',urlEncodeParser,(req,res)=>{
    if(req.body){
        res.send(req.body)
    }else{
        res.send('数据获取失败')
    }
})

app.listen(3000,()=>{
    console.log('服务已经启动...')
})
<body>
    <!-- <form action="http://127.0.0.1:3000/login" method="post"> -->
    <!-- 代码可以简写,只写路径 -->
        <form action="/login" method="post">
        用户名:<input type="text" name="username">
        <br>
        密码:<input type="password" name="password">
        <br>
        <button>登录</button>
    </form>
</body>

Node.js 学习笔记_第167张图片

8.防盗链

(1)介绍

防止外部网站盗用网站资源。
禁止该域名之外的其他网站访问这个资源Node.js 学习笔记_第168张图片

实现防盗链效果

在请求头中有一个 referer包含了发送请求的网站的协议、域名、端口。
Node.js 学习笔记_第169张图片
Node.js 学习笔记_第170张图片
如果referer不对,则返回404结果。

(2)练习

正常展示静态资源,使用localhost127.0.0.1都可以访问

const express =require('express');
const app=express();
app.use(express.static(__dirname+'/public'))

app.listen(3000,()=>{
    console.log('服务已经启动...')
})

Node.js 学习笔记_第171张图片
Node.js 学习笔记_第172张图片

添加防盗链效果:只有127.0.0.1域名可以访问。

const express = require('express');
const app = express();
//添加中间件,实现效果
app.use((req, res, next) => {
    // 获取referer
    let referer = req.get('referer')
    // 判断一下是否有referer
    if (referer) {
        // 实例化
        let url = new URL(referer)
        // 获取hostname域名
        let hostname=url.hostname
        console.log(hostname)
        if(hostname!=='127.0.0.1'){
            res.end('404')
            return
        }
    }
    next()
})
app.use(express.static(__dirname + '/public'))

app.listen(3000, () => {
    console.log('服务已经启动...')
})

Node.js 学习笔记_第173张图片
Node.js 学习笔记_第174张图片

9.路由模块化

  • express 中的 Router 是一个完整的中间件和路由系统,可以看做是一个小型的 app 对象。
  • 对路由进行模块化,更好的管理路由
  • router就相当于小型的app对象,就是把原来的app.get( )、app.post( )变成router.get( ) 、router.post()等。

(1)未导入时

没有路由组件时

//main.js文件
const express = require('express');
const app = express();
//引入子路由文件
// const homeRouter=require('./routers/homeRouter.js')
//设置和使用中间件
// app.use(homeRouter)

app.all('*',(req,res)=>{
    res.send('

404

'
) }) app.listen(3000,()=>{ console.log('3000 端口启动....'); })

Node.js 学习笔记_第175张图片
Node.js 学习笔记_第176张图片

(2)导入一个后

创建的路由文件的路径D:\web\node\init\routers\homeRouter.js

homeRouter.js
//1. 导入 express
const express = require('express');
//2. 创建路由器对象
const router = express.Router();
//3. 在 router 对象身上添加路由
router.get('/', (req, res) => {
res.send('首页');
})
router.get('/search', (req, res) => {
res.send('内容搜索');
});
//4. 暴露
module.exports = router;

Node.js 学习笔记_第177张图片
Node.js 学习笔记_第178张图片

(3) 两个都导入后

//1. 导入 express
const express = require('express');
//2. 创建路由器对象
const router = express.Router();
//3. 在 router 对象身上添加路由
router.get('/admin', (req, res) => {
res.send('管理页面');
})

//4. 暴露
module.exports = router;

Node.js 学习笔记_第179张图片

(4)设置路由前缀

Node.js 学习笔记_第180张图片

Node.js 学习笔记_第181张图片

修改后的user.js路由模块。

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

router.get('/test', function(req, res, next) {
  res.send('Flavia测试');
});

module.exports = router;

Node.js 学习笔记_第182张图片
因为在app.js中设置了路由前缀app.use('/users', usersRouter);,所以得输入 /users/test
Node.js 学习笔记_第183张图片

成功显示!

10.模版引擎

  • 模板引擎是分离 用户界面和业务数据 的一种技术。
  • EJS 是一个高效的 Javascript 的模板引擎。
  • 官网: https://ejs.co/
  • 中文站:https://ejs.bootcss.com/

Node.js 学习笔记_第184张图片

(1)理解

也就是分离服务器端的js和html
如下面的代码

const express=require('express');
//导入json文件
// 因为这个json文件里面有两层对象,所以使用解构赋值
const {singers}=require('./singers.json')
// console.log(singers)
const app=express();
app.get('/singer/:f.html',(req,res)=>{
    res.setHeader('content-type','text/html;charset=utf-8')
    let{f}=req.params;
    // 在数组中寻找对应id的数据
    let result=singers.find(item=>{
        if(item.id===Number(f)){
            return true;
        }
    });
    // console.log(result)
    //当请求的内容不在json数据里,就返回404
    if(!result){
        res.statusCode=404;
        res.end(`

404 Not Found

`
) return; } res.end(` Document

${result.singer_name}

`
) }) app.listen(3000,()=>{ console.log('服务已经启动,端口3000正在监听中...') })

我们要做的就是分离这部分Node.js 学习笔记_第185张图片

(2)初体验

注意 nrm use taobao 使用淘宝镜像。
下载安装EJS npm i ejs
Node.js 学习笔记_第186张图片
在ejs文件夹下装的,但是node_modules文件夹在ejs文件夹外部。
在这里插入图片描述

目的:我们要达到拼接效果,像下面代码所示,但是不想让str2变量和其他混在一起,这样不利于后续处理

const ejs=require('ejs')
let str1 ='你好'
let str2=`ejs${str1}`
console.log(str2)

在这里插入图片描述

<%= %> 是ejs解析内容的标记,作用是输出当前表达式的执行结果。
ejs会从后面传入的数据中找<%= %> 内的内容,并利用对应属性的值替换掉<%= %> 内的内容。

下面不同的写法,效果相同

const ejs=require('ejs')
let result=ejs.render('你好<%= str %>',{str:'ejs'})
console.log(result)
const ejs=require('ejs')
h='你好<%= str %>'
str='ejs'

let result=ejs.render(h,{str:str})
console.log(result)

const fs=require('fs')
const ejs=require('ejs')
hi=fs.readFileSync('./str.html').toString()
let result=ejs.render(hi,{str:'ejs'})
console.log(result)

str.html的内容
在这里插入图片描述

在这里插入图片描述

有点晕了

const fs=require('fs')
const ejs=require('ejs')

let ejsHtml=fs.readFileSync('./ejs.html').toString()
let str='ejs'
weather='今天天气不错'
let result=ejs.render(ejsHtml,{str,weather,ejsHtml})
console.log(result)


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2>你好<%= str %></h2>
    <%= weather %>
</body>
</html>

Node.js 学习笔记_第187张图片

(3)列表渲染

原生js实现

const palyer=['喜羊羊','美羊羊','懒羊羊','灰太狼']
let str='
    ' palyer.forEach(item=>{ str+=`
  • ${item}
  • `
    }) str+='
'
console.log(str)

在这里插入图片描述

使用ejs

(4)条件渲染

11.express-generator

安装命令npm install -g express-generator
在这里插入图片描述
创建命令express -e 名字

Node.js 学习笔记_第188张图片
所创建的文件夹目录
Node.js 学习笔记_第189张图片

  1. 安装依赖在这里插入图片描述

  2. 装好后的目录
    Node.js 学习笔记_第190张图片

  3. 通过 npm start 运行文件Node.js 学习笔记_第191张图片

  4. 进入
    Node.js 学习笔记_第192张图片

错误处理的两种方式
Node.js 学习笔记_第193张图片

12.文件上传

(1)上传效果实现

D:\web\node\init\ejs\generator\routes\index.js下的内容

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
//显示网页的表单
router.get('/upload',(req,res)=>{
  res.render('upload')
})
//处理文件上传
router.post('/upload',(req,res)=>{
  res.send('成功')
})

module.exports = router;

D:\web\node\init\ejs\generator\views\upload.ejs下的内容

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件上传</title>
</head>

<body>
    <h2>文件上传</h2>
    <hr>
    <!-- 文件上传时,必不可少的设置enctype -->
    <form action="/upload" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username">
        <br>
        头像:<input type="file" name="upload">
        <br>
        <button>点击提交</button>
    </form>

</body>

</html>

点击提交后的内容

Node.js 学习笔记_第194张图片
Node.js 学习笔记_第195张图片

(2)对上传文件进行处理

下载formidable

npm i formidable

Node.js 学习笔记_第196张图片

有bug
Node.js 学习笔记_第197张图片
Node.js 学习笔记_第198张图片

已经解决!!!!!!!!!!
看到弹幕说换个版本
然后试了一下npm i formidable@2没问题了


var express = require('express');
// const formidable =require('formidable')

var router = express.Router();
const formidable = require('formidable');
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
//显示网页的表单
router.get('/upload',(req,res)=>{
  res.render('upload')
})
//处理文件上传
router.post('/upload',(req,res)=>{
  // 创建form表单
  const form = formidable({multiples:true});
// 解析请求报文
  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
      
    }
    console.log('00')
    console.log(fields)
    console.log(files)
    res.send('ok')
  });
})

module.exports = router;

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件上传</title>
</head>

<body>
    <h2>文件上传</h2>
    <hr>
    <!-- 文件上传时,必不可少的设置enctype -->
    <form action="/upload" method="post" enctype="multipart/form-data">
        用户名:<input type="text" name="username">
        <br>
        头像:<input type="file" name="upload">
        <br>
        <button>点击提交</button>
    </form>

</body>

</html>

Node.js 学习笔记_第199张图片
Node.js 学习笔记_第200张图片

(3)保存文件

router.post('/upload',(req,res)=>{
  // 创建form表单
  const form = formidable({
    multiples:true,
    //设置文件的保存路径
    uploadDir:__dirname+'/../public/images',
    // 保存文件后缀名
    keepExtensions:true
  });
// 解析请求报文
  form.parse(req, (err, fields, files) => {
    if (err) {
      next(err);
      return;
    }
    console.log(fields)
    console.log(files)
    res.send('ok')
  });
})

Node.js 学习笔记_第201张图片

让用户获得图像

let url='/images/'+files.upload.newFilename
    // 学完数据库,将此数据保存在数据库中
    res.send(url)

注意大小写newFilename是对的
Node.js 学习笔记_第202张图片
Node.js 学习笔记_第203张图片

你可能感兴趣的:(node.js)