Bootstrap

NodeJs的基本使用

Node.js

1.入门

1.下载

下载 | Node.js 中文网 (nodejs.cn)

2.初识 Node.js

Nodejs@ is a JavaScript runtime built on Chrome’s V8 JavaScript engine.

Node.js 是一个基于Chrome V8引擎的JavaScript 运行环境。

Node.js 的官网地址:https://nodejs.org/zh-cn/

3.fs 文件系统模块

1.什么是fs 文件系统模块

fs 模块是Node.js官方提供的、用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求。

例如:

fs.readFile()方法,用来读取指定文件中的内容

fs.writefile()方法,用来向指定的文件中写入内容

如果要在JavaScript代码中,使用fs模块来操作文件,则需要使用如下的方式先导入它:

const fs = require(‘fs’)

2.fs 文件系统模块

1.读取指定文件中的内容

fs.readFile()的语法格式

使用 fs.readFile()方法,可以读取指定文件中的内容,语法格式如下:

1 fs.readFile(path,[options], callback)

参数1:必选参数,字符串,表示文件的路径

参数2:可选参数,表示以什么编码格式来读取文件

参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果

2.向指定的文件中写入内容

1.fs.writeFile()的语法格式

使用 fs.writeFile0方法,可以向指定的文件中写入内容,语法格式如下:

1 fs.writeFile(file, data,[options], callback)

参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径

参数2:必选参数,表示要写入的内容

参数3:可选参数,表示以什么格式写入文件内容,默认值是 utf8

const fs=require('fs');

/* fs.readFile("1.txt","utf-8",function(err,dataStr)
{
    console.log(dataStr);
}) */

/* fs.writeFile("1.txt","ik","utf-8",function(err){
    console.log(err);
}) */

fs.readFile("1.txt","utf-8",function(err,dataStr)
{
    const arrNew=[];
    const arr = dataStr.split(' ');

    arr.forEach(item=>{
        arrNew.push(item.replace('=',':'));
    })
    const garr=arrNew.join('\r\n');
    console.log(arr);
    console.log(arrNew);
    console.log(garr);
    fs.writeFile('2.txt',garr,'utf-8',function(err){
        console.log(err);
    })
})

2.路径

1.路径的拼接

路径的拼接使用join方法

const path = require("path");

const pathStr = path.join('/a','/b/c','../../','./d','e');

console.log(pathStr);

__dirname 路径名

2.获取路径中的文件名

basename

path1="1.txt";
const str = path.basename(path1,".txt");
console.log(str);

3.获取文件的后缀名

extname

const fpath= "1.txt";
const ftxt = path.extname(fpath);
console.log(ftxt);

小脚本

const fs =require("fs");
const path = require("path");

const regStyle = /<style>[\s\S]*<\/style>/
const regScript = /<script>[\s\S]*<\/script>/

fs.readFile("./index.html",'utf-8',function(err,dataStr){
    if (err) return console.log("读取失败"+err.message);
    resolveCSS(dataStr);
    resolveScript(dataStr);
    resolveHTML(dataStr);
})

function resolveCSS(htmlstr){
    const str1 = regStyle.exec(htmlstr);
    const nstr = str1[0].replace('<style>','').replace('</style>','');
    fs.writeFile(path.join(__dirname,'/clcok.css'),nstr,function(err,dataStr){
        if (err) return console.log("写入失败");
        console.log("写入成功");
    })
}

function resolveScript(htmlstr1){
    const str2 = regScript.exec(htmlstr1);
    const nstr2 = str2[0].replace('<script>','').replace('</script>','');
    fs.writeFile(path.join(__dirname,'/clcoks.js'),nstr2,function(err,dataStr){
        if (err) return console.log("写入失败");
        console.log("写入成功");
    })
}

function resolveHTML(htmlstr){
    const html = htmlstr.replace(regStyle,'<link rel="stylesheet" href="./clcok.css">').replace(regScript,'<script src="./clcoks.js"></script>');
    fs.writeFile('index.html',html,function(err,dataStr){
        if (err) return console.log("写入失败");
        console.log("写入成功");
    })
}

后写入的内容会覆盖之前写入的内容

3.http模块

1.导入http模块

const http = require(‘http’)

const http = require('http')


const serve = http.createServer()

serve.on('request',(req,res)=>{
    console.log("web serve start");
})

serve.listen(1910,()=>{
    console.log("port:"+1910);
})

req.url 获取网址

req.method 获取请求方式

serve.on('request',function(req,res){
    const url = req.url;
    const method  = req.method;
    console.log(url+"   "+method);
})

解决中文乱码

res.setHeader(‘Content-Type’,‘text/html; charset=utf-8’);

const http = require('http');

const serve =http.createServer();

serve.on('request',function(req,res){
    const url = req.url;
    const method  = req.method;
    console.log(url+"   "+method);
    const str = "启动";
    res.setHeader('Content-Type','text/html; charset=utf-8');
    res.end(str);

})

serve.listen(1910,function(){
    console.log("启动");
})
const http = require('http');

const serve = http.createServer();

serve.on('request',function(req,res){
    const url = req.url;

    let content = '404 Not Found';

    if (url === '/' || url === '/index.html'){
        content = '<h1>首页</h1>'
    }else if (url === '/other.html'){
        content = '<h2>其他</h2>'
    }

    res.setHeader('Content-Type','text/html; charset=utf-8');

    res.end(content);
})

serve.listen(1910,function(){
    console.log("启动服务");
})

5.小案例

const fs = require("fs");
const http = require("http");
const path = require("path");

const serve = http.createServer();

serve.on('request',(req,res)=>{
    const url = req.url;
    const str1 = path.join(__dirname,url);
    console.log(str1);
    fs.readFile(str1,'utf-8',function(err,dataStr){
        if (err) return res.end("404 Not found");
        res.end(dataStr);
    })
})

serve.listen(1910,function(){
    console.log("启动");
})

4.模块化

1.模块的规范性

模块化规范就是对代码进行模块化的拆分与组合时,需要遵守的那些规则。

例如:

使用什么样的语法格式来引用模块

在模块中使用什么样的语法格式向外暴露成员

模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用利人利己

2.Node.js模块

  • 内置模块 fs path http
  • 自定义模块 .js 用户创建
  • 第三方模块 第三方开发的模块

加载模块

require()

3.模块作用域

在自定义模块中的变量、方法等成员,只能在当前模块内被访问,这种模块级别的限制就叫做模块作用域

好处

  • 防止全局变量被污染

向外共享模块作用域中的成员

moudule对象

存储和当前模块有关的信息

moudule.exports对象

可以将模块的成员共享出去,供外界使用

在外界用require()导入自定义模块得到moudule.exports对象

默认情况下moudule.exports等于空对象

module.exports.uname = "zs";

module.exports.say = function(){
    console.log("Hi");
}

以moudule.exports指向的对象为准

module.exports.uname = "zs";

module.exports.say = function(){
    console.log("Hi");
}

module.exports = {
    nuname : 'ls',
    nsay(){
        console.log("HHi")
    }
}

exports对象

moudule.exports对象与exports对象指向同一个对象

exports.uname='ls';

exports.age=19;

建议不要在同一个文件使用moudule.export、exports

4.CommonJS规范

1.每个模块的moudule代表当前模块

2.moudule变量是一个对象,moudule.export是一个接口

3.require()用来加载模块

5.npm包

1.格式化时间

function dateformat(dastr){
    function zero(str){
        if (str<10) return '0'+str
    }
    const dt = new Date(dastr);

    const m = dt.getFullYear();

    const n = zero(dt.getMonth());

    const d = zero(dt.getDay());

    return `${m}-${n}-${d}`;
}

module.exports.dateformat=dateformat;
const req = require("./time")

const dt = new Date();

const s = req.dateformat(dt);

console.log(s)

2.

npm install 包名

简写

npm i 包名

const moment = require("moment");

const dt = moment().format('YYYY-MM-DD');

console.log(dt);

npm i moment@版本 安装指定版本的包

3.包的语义化版本规范

2.24.0

  • 1->大版本
  • 2->功能版本
  • 3->Bug修复版本

4.包管理配置文件

快速创建package.json文件

npm init -y

要在gitingnore文件添加node_modules

5.dependencies

用来记录使用npm下载了哪些包

npm i 直接安装所有包

npm uninstall 包名 卸载包

6.devDependencies

某些包只在开发阶段使用,加入devDependencies节点

某些包在开发使用上线也需要使用,加入dependencies节点

npm install webpack -D

7.镜像源

查看当前镜像源

npm config get registry

npm config set registry=https://registry.npm.taobao.org/

nrm

方便地切换镜像源

npx nrm ls

npx nrm use taobao

8.包的分类

项目包,被安装到node_moudules目录

  • 开发依赖包 devDependencies
  • 核心依赖包 dependencies

全局包,在使用npm install 加上-g参数

C:\Users\用户名\AppData\Roaming\npm\node_modules

npm uninstall 包名 -g

i5ting_toc

可以把md转成html

npm install -g i5ting_toc

i5ting_toc -f .md -o

9.包的规范

1.单独目录存在

2.有文件package.json

3.有name,version,main三个属性,包名,版本号,包的入口

10.自定义包

新建文件夹作为根目录

1.package.json

2.index.js

3.README.md

function htmlEscape(htmlstr){
    return htmlstr.replace(/<|>|"|&/g,match=>{
        switch (match){
            case '<':
                return '&lt;';
            case '>':
                return '&gt;'
            case '"':
                return '&quot;'
            case '&':
                return '&amp;'
        }
    })
}

function htmlUnEscape(htmlstr){
    return htmlstr.replace(/&lt;|&gt;|&quot;|&amp;/g,match=>{
        switch (match){
            case '&lt;':
                return '<';
            case '&gt;':
                return '>'
            case '&quot;':
                return '"'
            case '&amp;':
                return '&'
        }
    })
}

module.exports={
    htmlEscape,
    htmlUnEscape
}

模块拆分

src

const html = require("./src/html")
const unhtml = require("./src/unhtml")

module.exports={
    ...html,
    ...unhtml
}

11.发布npm包

1.注册npm账号

2.登录 npm login

3.npm publish 发布

4.删除包 npm unpublish 包名 --force

只能删除72小时以内发布的包

删除的包,在24小时内不允许发布没有意义的包

12.模块的加载机制

模块加载一次后会被缓存

内置模块加载优先级最高

在载入内置模块是要以./或…/开头

默认加载main入口,如果没找到,会找index.js否则报错

6.Express

1.基本使用

获取url中携带的参数

req.query

2.获取url中的动态参数

const express = require("express");

const app = express();

app.all("/serve/:id",function(req,res){
    console.log(req.params);
    const str = JSON.stringify(req.params)
    res.end(str)
})

app.listen(4400,()=>{
    console.log("启动服务");
})

3.托管静态资源

express.static0)

创建一个静态资源服务器,通过如下代码就可以将public目录下的图片、CSS文件、JavaScript 文件对外开放访问了:

app.use(express.static(‘public’))

app.use(‘/file’,express.static(‘public’))

http://localhost:3000/images/bg.jpg

http://localhost:3000/css/style.css

http://localhost:3000/js/login.js

注意:Express 在指定的静态目录中查找文件,并对外提供资源的访问路径

因此,存放静态文件的目录名不会出现在URL中

有多个静态资源目录就多次调用这个函数

4.路由模块

const express = require("express");

const router = express.Router();

router.get("/serve/:id",function(req,res){
    console.log(req.params);
    const str = JSON.stringify(req.params);
    res.end(str);
})

router.post("/serve",function(req,res){
    console.log("POST");
    res.end("123");
})

module.exports = router;
const express = require("express");

const app = express();

const router = require('./model1')

app.use(router);

app.listen(4400,()=>{
    console.log("启动服务");
})

7.中间件

1.简介

本质是一个function处理函数

必须包含next函数,路由处理函数只包含req和res

next->把流转关系交给下一个中间件和路由

const mv = function(req,res,next){
    console.log("中间件函数");
    next();
}
//将mv注册为全局生效的中间件
app.use(mv);

2.简写形式

app.use(function(req,res,next){
    console.log("中间件");
    next();
})

3.在中间件挂载属性

app.use(function(req,res,next){
    console.log("中间件");
    const time =new Date()
    req.stime = time;
    next();
})

app.all('/',(req,res)=>{
    console.log(req.stime);
    res.end(req.stime)
})

4.定义多个全局中间件

多次调用use方法

const express = require("express");

const app = express();

app.use(function(req,res,next){
    console.log("1");
    next();
})

app.use(function(req,res,next){
    console.log("2");
    next();
})

app.all('/',(req,res)=>{
    res.end("1")
})

app.listen(4400,()=>{
    console.log("启动服务");
})

5.局部生效的中间件

不适用app.use()声明

const express = require("express");

const app = express();

const mv = function(req,res,next){
    console.log("局部中间件");
    next();
}

app.all('/',mv,(req,res)=>{
    res.send("HOME");
})

app.listen(4400,()=>{
    console.log("启动服务");
})

定义多个中间件

const mv1 = function(req,res,next){
    console.log("局部中间件1");
    next();
}

const mv2 = function(req,res,next){
    console.log("局部中间件2");
    next();
}

app.all('/serve',mv1,mv2,(req,res)=>{
    res.send("HOME1");

})
app.all('/serve',[mv1,mv2],(req,res)=>{
    res.send("HOME1");
})

mv1,mv2 === [mv1,mv2]

6.注意事项

一定要在路由的之前定义中间件

客户端发过来的请求,可以连续调用多个中间件进行处理

执行完中间件代码后要调用next函数

next函数后面不要再写代码

连续调用多个中间件时,连续多个中间件共享req和res对象

7.中间件的分类

5大类

应用级别的中间件

绑定到了app.use,app.get,app.post,绑定到了app实例上的中间件

路由级别的中间件

绑定到express.Router

错误级别的中间件,用来捕获整个项目发生的异常错误,从而防止项目异常崩溃

(err,req,res,next)

express内置的中间件

express.static 托管静态资源

express.json 解析JSON格式的请求实体数据

express.urlencoded 解析URL-encoded格式的请求实体数据

const express = require("express");

const app = express();

app.use(function(req,res,next){
    console.log("1");
    next();
})

/* 配置解析json格式的数据 */
app.use(express.json)
app.use(express.urlencoded({extented:false}))
app.post('/serve',(req,res)=>{
    /* req.body获取请求体的数据 */
    console.log(req.body);
    res.end(req.body)
})

app.listen(4400,()=>{
    console.log("启动服务");
})

第三方中间件

require()

app.use()

8.自定义中间件

const express = require("express");
const app = express();


const qs = require("querystring");
/* 数据量较大无法一次传输完 */
const mymod = function(req,res,next){
    /* 监听data事件 */
    let str=''
    req.on('data',(Chunk)=>{
        str += Chunk;
    })
    /* 当数据接受完毕会触发end事件 */
    req.on('end',()=> {
        const body = qs.parse(str);
        req.body=body;
        next();
    })
}

module.exports = mymod;
const express = require("express");
const mymod = require("./moudule");

const app = express();
app.use(mymod);

app.post('/',function(req,res){
    console.log(req.body);
    res.end("end");
})

app.listen(4400,()=>{
    console.log("启动服务");
})

9.接口跨域问题

1.cors中间件

1.npm i cors

2.const cors = require(“cors”)

3.app.use(cors)

CORS

由一系列HTTP响应头组成

在服务端进行配置,不需要做额外配置

在浏览器中有兼容性

const express = require("express");
const cors = require("cors");
const app = express();

app.use(cors());

app.all('/',(req,res)=>{
    res.send("a");
})

app.listen(4400,()=>{
    console.log("启动");
})

10.前后端的身份认证

npm i jsonwebtoken
npm i express-jwt

1.导入JWT相关的包

const express = require('express');

const app = express();

const jwt = require("jsonwebtoken");
const expressjwt = require("express-jwt");

app.listen(4400,()=>{
    console.log("qd");
})

2.secret密钥

const secretKey = “-hi”;

3.生成jwt字符串

jsonwebtoken的sign()方法

app.all('/',(req,res)=>{
    const tokenstr=jwt.sign({username:'zs'},secret,{expiresIn:'30s'});
    res.send({
        status:200,
        message:"dl",
        token:tokenstr
    })
})

4.解析还原成JSON对象

express-jwt

app.use(expressjwt({secret:secret})).unless({path:[/^\/api\//]})
//secret->密钥
//unless不需要解析的路径
const jwt = require("jsonwebtoken");
const { expressjwt:expressJWT } = require("express-jwt");
const secret = "^-^hi";
app.use(expressJWT({secret:secret, algorithms:['HS256']}));

5.捕获错误信息

定义一个全局的中间件

app.use((err,req,res,next)=>{
    //if (err.name=)
})

11.node项目

1.创建项目

npm init -y

安装express

const express = require("express");

const app = express();

app.listen(4400,()=>{
    console.log("启动服务器");
})

配置cors跨域

const cors = require("cors");

app.use(cors);

配置表单解析的中间件

//解析x-www格式
app.use(express.urlencoded({extended:false}));

安装mysql,创建数据库和数据库表

npm i mysql

创建db文件夹和index.js

const mysql =require("mysql");

const db = mysql.createPool({
    host:'127.0.0.1',
    user:'root',
    password:'12345678',
    database:'test'
})

module.exports=db;

注册用户相关功能的实现

const { request } = require("express");

/* 导入数据库操作模块 */
const db = require("../dp/index.js")



exports.reguser=(req,res)=>{
    const mes = req.body;
    if (!mes.username || !mes.password){
        res.end("error");
    }
    const sqlstr = "select * from ev_users where username=?"
    db.query(sqlstr,mes.username,(err,results)=>{
        if (err){
            return res.send({
                status:200,
                Message:err.message
            })
        }
        if (results.length > 0){
            return res.send({
                status:200,
                Message:"用户名被占用"
            })
        }else{
            res.send("reg ok");
        }
    })
    //res.send("reg ok");
}

exports.loguser=(req,res)=>{
    res.send("log ok");
}

对密码进行加密

bcryptjs

npm i [email protected]

const bcrypt=require("bcryptjs");
mes.password = bcrypt.hashSync(mes.password,10);

生成jwt的Token字符串

npm i jsonwebtoken

const user = {...results[0],password:'',user_pic:''};
const tokenstr = jwt.sign(user,config.jwtSecretKey,{expiresIn: config.experiments})
res.send({
    status:200,
    message:"登录成功",
    token:'Bearer '+tokenstr
});

解析token的中间件

npm i [email protected]

app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:/^\/login/}));
;