黑马程序员Node.js全套入门教程,nodejs最新教程含es6模块化+npm+express+webpack+promise等_Nodejs实战案例详解_哔哩哔哩_bilibili本套课程作为框架前置课,重点为学生铺垫 npm、包、模块化、身份认证、CORS 跨域等主要知识点,为学习后面的 Vue 课程夯实基础。同时,本课程涵盖了 MySQL 数据库、API 接口项目开发等后端内容,拓宽了学生的知识面,为前端学生构建了前后端完整的知识体系,助力学生更好地发展。
https://www.bilibili.com/video/BV1a34y167AZ?p=37&spm_id_from=333.1007.top_right_bar_window_history.content.click三. http模块
http模块用来创建web服务器,对外提供网络资源。
- Node.js中无需IIS和Apache等disanfangweb服务器软件,可以直接通过http模块手写一个服务器软件。
- 服务器的相关概念:IP地址、域名和域名服务器、端口号
1. 创建web服务器的基本步骤
- req请求对象:在request事件处理函数中,访问与客户端相关的数据或属性。
- res响应对象:在request事件处理函数中,访问与服务器相关的数据或属性。
- 在终端退出服务器:control+C
//1、导入http模块
const http=require('http');
//2、创建web服务器实例
const server=http.createServer();
//3、为服务器实例绑定request事件,即可监听客户端发送过来的网络请求
server.on('request',function(req,res){
console.log("Someone visit our web server.");
//req是请求对象,它包含了与客户端相关的数据和属性
// req.url是客户端请求的URL地址
const url=req.url;
// req.method是客户端的method请求类型
const method=req.method;
const str=`Your request url is ${url},and request method is ${method}`;
// 为了防止中文乱码问题,需要设置响应头 Content-Type的值为text/html; charset=utf-8
res.setHeader('Content-Type','text/html; charset=utf-8');
//res是响应对象,用于访问与服务器相关的数据或属性
// 调用res.end()方法,向客户端响应一些内容
res.end(str);
});
//4、启动服务器
server.listen(8080,function(){
console.log("server running at http:127.0.0.1:8080")
});
2. 解决中文乱码问题
问题:调用res.end()方法向客户端发送中文内容时会出现乱码问题。
解决方法:手动设置内容的编码格式
// 为了防止中文乱码问题,需要设置响应头 Content-Type的值为text/html; charset=utf-8
res.setHeader('Content-Type','text/html; charset=utf-8');
3. 根据不同的url相应不同的html内容
const http=require('http');
const server=http.createServer();
server.on('request',(req,res)=>{
console.log("Someone visit our web server.");
const url=req.url;//1、获取请求的url地址
let content='<h1>404 Not found!</h1>';//2、设置默认的响应内容为404 Not found
if(url==='/'||url==='/index.html'){//3、判断用户请求的是否为/或/index.html页面
content='<h1>首页</h1>';
}else if(url==='/about.html'){//4、判断用户请求的是否为/或/about.html页面
content='<h1>关于页面</h1>';
}
res.setHeader('Content-Type','text/html; charset=utf-8');//5、设置Content-Type响应头,防止中文乱码
res.end(content);//6、使用res.end()把内容响应给客户端
});
server.listen(80,()=>{
console.log("server running at http:127.0.0.1:80");
});
4. 实现html页面的web服务器
把文件的实际存放路径,作为每个资源的请求url地址
服务器充当的角色就是一个字符串的搬运工
const http=require('http');
const fs=require('fs');
const path=require('path');
const server=http.createServer();
server.on('request',(req,res)=>{
//1、将资源的请求url地址映射为文件的存放路径 http://127.0.0.1/clock/index.html
const url=req.url;//获取客户端请求的url地址 /clock/index.html
//const fpath=path.join(__dirname,'./file',url);//把请求的url地址映射为本地文件的存放路径
//1.1 优化资源的请求路径
let fpath='';
if(url==='/'){ // http://127.0.0.1/
fpath=path.join(__dirname,'./file/clock/index.html');
} else { //http://127.0.0.1/index.html
fpath=path.join(__dirname,'./file/clock',url);
}
//2、读取文件内容并相应给客户端
fs.readFile(fpath,'utf8',(err,dataStr)=>{
if(err) return console.log("404 not found.");
res.end(dataStr);
});
});
server.listen(80,()=>{
console.log("server running at http:127.0.0.1:80");
});
四. 模块化
模块化是指解决问题时,自顶向下逐层把系统划分成若干模块的过程。模块是系统中可组合、分解和更换的单元。
- 编程中的模块化:遵守固定的规则(模块化规范),把一个大文件拆成独立并相互依赖的多个小模块,提高代码的复用性、维护性,可以实现按需加载。
- Node.js中模块的分类(按来源分):内置模块、自定义模块、第三方模块。
1. 加载模块:require()
使用require()方法加载其它模块时,会执行被加载模块中的代码。
使用require()家在用户自定义模块期间,可以省略.js的后缀名。
//加载用户自定义模块
const m1=require('./file/2.js');//也可以省略.js后缀名
2. 向外共享模块作用域中的成员
模块作用域:防止了全局变量污染的问题
(1)module对象,存储了和当前模块有关的信息。
- module.exports对象,在自定义模块中可以使用它,将模块内的成员共享出去,供外界使用。
- 外界使用require()方法导入自定义模块时,得到的就是module.exports所指的对象。
//在外界使用require导入一个自定义模块的时候,得到的成员就是那个模块中module.exports所指向的对象
const m=require('./file/2.js');
console.log(m);
//2.js 文件
//在一个自定义模块中,默认情况下module.exports={}
const age=20;
//向module.exports上挂载username属性,也可以写为exports.username="zs";
module.exports.username="zs";
//向module.exports上挂载sayHello方法
module.exports.sayHello=function(){
console.log('大家好,我是'+username);
}
//module.exports.age=age;
(2)exports对象,默认情况下和module.exports指向同一个对象,最终共享的结果以module.exports指向的对象为准。
- 用来简化向外共享成员的代码。
- 注意:require()模块时,得到的永远是module.exports所指的对象。
- 注意:为了防止混乱,不要在同一个模块中同时使用exports和module.exports。
3. CommonJS模块化规范
- 每个模块内部,module变量代表当前模块。
- module变量是一个对象,它的exports属性(即module.exports)是对外的接口。
- 加载某个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块。
4. 模块的加载机制
- 优先从缓存中加载
- 模块在第一次加载后会被缓存,多次调用require()不会导致模块的代码被执行多次。
- 可以提高模块的加载效率。
- 内置模块的加载机制
- 内置模块的加载优先级最高
- 自定义模块的加载机制
- 使用require()加载自定义模块时,必须指定以./或../开头的路径标识符。否则node会把它当做内置模块或第三方模块加载。
- 使用require()加载自定义模块时,若省略了文件扩展名,node会依次尝试加载:(1)按确切文件名进行加载(2)补全.js扩展名进行加载(3)补全.json扩展名进行加载
- 第三方模块的加载机制
- 使用require()加载模块时,若模块不是内置模块,且没有以./或../开头,则node会从当前模块父目录开始尝试从/node_modules文件夹中加载第三方模块。
- 若没有找到对应的第三方模块,则移动到上一层父目录中进行加载,指导文件系统的根目录。
- 目录作为模块时有三种加载方式
- (1)在被加载的目录下找一个叫package.json的文件,并寻找main属性,作为require()加载的入口。
- (2)若目录中没有package.json文件,或main入口不存在或无法解析,node会试图加载目录下的index.js文件。
- (3)若以上两步都失败,node会在终端打印错误消息,报告模块缺失。
五. npm与包
包===第三方模块
- 包共享平台(搜索):npm
- 包共享服务器(下载):https://registry.npmjs.org/
- 包管理工具(下载包):终端中输入 npm -v
- 安装包: npm install 包完整的名称
- 安装包(简写形式): npm i 包完整的名称
- 安装指定版本的包: npm i 包完整的名称@版本号
- 包的语义化版本规范:点分十进制,共三位数组
- 第一位数字:大版本
- 第二位数字:功能版本
- 第三个数字:Bug修复版本
- 解决包下载慢的问题:淘宝npm镜像服务器
- 查看当前的下包镜像源:npm config get registry
- 切换npm的下包镜像源方式1:npm config set registry=https://registry.npm.taobao.org/
- 切换npm的下包镜像源方式2:(1)安装nrm工具: npm i nrm -g(2)查看所有可用镜像源:nrm ls(3)将下包镜像源切换为淘宝镜像:nrm use taobao
- 初次装包后项目文件夹下多了node_modules文件夹和package-lock.json配置文件。
- node_modules文件夹:存放所有已安装到项目的包。require()导入第三方包时,就是从这个目录中查找并加载包。
- package-lock.json配置文件:记录node_modules目录下每一个包的下载信息,例如包的名字、版本号、下载地址等。
- 包管理配置文件:package.json,放在项目的根目录中,记录与项目有关的配置信息。
- 多人协作问题:第三方包体积过大,不方便共享项目源代码。package.json记录安装了那些包,从而方便剔除。
- 项目开发中,一定要把node_modules文件夹添加到.gitignore忽略文件中。
- 当拿到一个剔除了node_modules的项目之后,需要先把所有的包下载到项目中。
- 一次性安装所有包:npm install
- 一次性安装所有包(简写形式):npm i
- 卸载包: npm uninstall 包完整的名称
- 执行成功后,会把卸载的包自动从package.json的dependencies中移除。
- 快速创建package.json文件: npm init -y
- 只需要在项目刚建立时,在项目的根目录中执行一次,目录和项目名称必须不包含中文和空格。
- dependencies节点:专门用来记录使用npm install命令装了哪些包,这些包项目开发和上线阶段都会用到。
- devDependencies节点:记录只会在项目开发阶段用到,项目上线之后不会用到的包。
- 将包记录到devDependencies节点:npm install 包名 --save-dev
- 将包记录到devDependencies节点(简写形式):npm i 包名 -D
- 多人协作问题:第三方包体积过大,不方便共享项目源代码。package.json记录安装了那些包,从而方便剔除。
- 包的分类:(1)项目包(开发依赖包、核心依赖包)、(2)全局包(npm install 时提供了-g参数,卸载时也要提供-g参数。只有工具性质的包才需全局安装。)
- 规范的包结构:
- 包必须以单独的目录存在
- 包的顶级目录下必须包含package.json
- package.json中必须包含name、version、main三个属性,分别代表包的名字、版本号、包的入口
1. 格式化时间
# 在终端中下载包
npm i moment
//1、导入moment包
//注意:导包的名称就是安装包时的名称
const moment=require('moment');
//2、参考moment官方API文档,使用moment
const dt=moment().format('YYYY-MM-DD HH:mm:ss');
console.log(dt);
2. 开发属于自己的包
(1)新建文件夹作为包的根目录
(2)在文件夹中新建三个文件:
- package.json(包管理配置文件)
- index.js(包的入口文件)
- README.md(包的说明文档):安装方式、导入方式、功能及使用方式、开源协议
//package.json文件
{
"name":"songd-tools",
"version":"1.0.0",
"main":"index.js",
"description": "提供了格式化时间,HTMLEscape的功能",
"keywords": ["dateFormat","escape"],
"license": "ISC"
}
//index.js文件
//这里是包的入口文件
const date=require('./src/dateFormat');
const escape=require('./src/htmlEscape');
//向外暴露需要的成员
module.exports={
...date,
...escape
}
//README.md
## 安装
```
npm install songd-tools
```
## 导入
```js
const songd=require('songd-tools')
```
## 格式化时间
```js
//调用dateFormat对时间进行格式化
const dt=sdutil.dateFormat(new Date());
//结果 2022-04-01 17:48:20
console.log(dt);
```
## 转义HTML中的特殊字符
```js
//待转换的HTML字符串
const htmlStr='<h1 title="abc">这是h1标签<span>123 </span></h1>';
//调用htmlEscape方法进行转换
const newStr=sdutil.htmlEscape(htmlStr);
//转换的结果 &lt;h1 title=&quot;abc&quot;&gt;这是h1标签&lt;span&gt;123&amp;nbsp;&lt;/span&gt;&lt;/h1&gt;
console.log(newStr);
```
## 还原HTML中的特殊字符
```js
//待还原的HTML字符串
const str=sdutil.htmlUnEscape(newStr);
//还原的结果 <h1 title="abc">这是h1标签<span>123 </span></h1>
console.log(str);
```
## 开源协议
ISC
(3)在文件夹中新建src文件夹,并创建两个文件
//dateFormat.js文件
//格式化时间的函数
function dateFormat(dtStr){
const dt=new Date(dtStr);
const y=dt.getFullYear();
const m=padZero(dt.getMonth()+1);
const d=padZero(dt.getDate());
const hh=padZero(dt.getHours());
const mm=padZero(dt.getMinutes());
const ss=padZero(dt.getSeconds());
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
//补零的函数
function padZero(n){
return n>9?n:'0'+n;
}
//向外暴露需要的成员
module.exports={
dateFormat
}
//htmlEscape.js文件
//转译html的函数,把html字符转译成实体字符
function htmlEscape(htmlStr){
return htmlStr.replace(/<|>|"|&/g,(match)=>{
switch(match){
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case "&":
return '&'
}
})
}
//还原html的函数
function htmlUnEscape(htmlStr){
return htmlStr.replace(/<|>|"|&/g,(match)=>{
switch(match){
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case "&":
return '&'
}
})
}
//向外暴露需要的成员
module.exports={
htmlEscape,
htmlUnEscape
}
3. 发布包
(1)登录npm账号
- 把下包的服务器地址切换为npm官方服务器
- 在终端执行npm login命令,依次输入用户名、密码、邮箱
(2)把包发布到npm上
- 把终端切换到包的根目录
- 运行npm publish命令(注意:包名不能雷同!)
(3)删除已发布的包
- 运行 npm unpublish 包名 --force命令,即可从npm删除已发布的包
- npm unpublish删除的包,在24小时以内不允许重复发布
- npm unpublish命令只能删除72小时以内发布的包