node知识+Express框架

859 阅读3分钟

一、 node安装

  • 建议安装长期支持版
  • 可以使用nvm安装多个版本的Node

真实项目中的数据存储,都是用数据库

  • 配合node的配关系型数据库
  • 关系型数据库
    • MySQL
    • SQLserve
    • oracle

1.)什么是node

  • node是一套基于V8引擎渲染和解析JS的工具或环境
    • 说node是后台语言,是因为:我们在服务器端安装node,这样就可以基于JS编写一些后台处理程序,最后交给node执行
    • 所以说JS是“全栈”编程语言:同一个技术栈,既可以完成客户端开发,也可以完成服务端开发

2.) node的新特性

  • 基于V8引擎渲染解析JS[相同点]
  • 提供I/O操作「文件的读写操作」
    • I: input输入
    • O: output输出
    • JS在客户端浏览器中运行,能否对客户端本地的文件进行读写操作?
      • 不能
      • input:type='file'【文件上传(用户自己选择上传的)】
    • JS在服务器端运行(基于Node运行),能否对服务器端的文件进行操作?
      • node赋予了JS操作I/O的能力【fs内置模块】【特点】
  • window & global
    • 浏览器中运行JS,全局对象是window 【特点】
      • setInterval
      • setTimeout
    • Node中运行JS,全局对象是global【特点】
      • process:node中进程管理属性
        • process.nextTick()【微任务中优先级最高,永远被最先执行】
        • process.env 环境变量
      • Buffer【进制编码格式数据】
      • setImmediate【异步宏任务】

3.)在node端运行JS

  • 编写JS文件,直接基于"node xxx.js"
    • this -> 当前模块
    • queueMicrotask
      • 创建一个异步的微任务
      • 客户端和Node端都支持
      • 用法:
用法:
queueMicrotask(function(){
     // 这个函数必须在同步任务执行完,去EventQueue中找异步微任务的时候执行

})
  • REPL命令模式 "输入$ node,即可开启类似于浏览器控制台的REPL模式"
    • this -> global

4.) cross-env模块:用来设置环境变量

// package.json
"scripts": {
  "start": "cross-env NODE_ENV=development node 1.js",
  "build": "cross-env NODE_ENV=production node 1.js"
}

// 1.js
console.log(process.env.NODE_ENV);
  • $ npm i cross-env --save-dev
  • 这样再执行不同的脚本命令时[$npm run xxx],因为设置了不通过的环境变量,而我们在JS文件中可以获取设置的环境变量值...这样我们可以根据不同的环境变量,处理不同的事情
    • 在axios的二次配置,我们完全可以基于环境变量得知是开发环境还是生产环境,或则是测试环境等...然后根据不同的环境,让API请求的公共前缀baseURL设置不同值
    • 如果自己配置webpack,那么久需要基于环境变量不同,区分不同的环境,从而写出不同的webpack配置规则;【@vue/cli脚手架内部也就是这样完成的】

image.png

5.)node中的事件循环机制

console.log('start');
setTimeout(() => {
    console.log(1);
}, 0);
setTimeout(() => {
    console.log(2);
    setTimeout(() => {
        console.log(3);
    }, 0);
    setImmediate(() => {
        console.log(4);
    });
}, 100);
Promise.resolve().then(() => {
    console.log(5);
});
setImmediate(() => {
    console.log(6);
});
process.nextTick(() => {
    console.log(7);
    process.nextTick(() => {
        console.log(8);
    });
});
Promise.resolve().then(() => {
    console.log(9);
});
console.log('end');

分析过程 微信图片_20210707140705.png

setImmediate

  • setImmediate Node中新提供的定时器【异步】
    • 在同步代码执行中设置的setImmediate,等价于setTimeout时间设置为零
    • 但是如果是在某个异步任务执行的时候设置的setImmediate,则它是异步宏任务队列中优先级最高

CommonJS模块规范

  • 导出:module.exports
  • 导入:require
  • node模块
    • 内置模块
    • 第三方模块
    • 自定义模块

导入内置模块和第三方模块是不需要加路径【查找机制:现找本地node——modules文件夹,如果找不到这个模块,再去内置模块中找...】

导入自定义模块一定要加路径[js后缀可以省略]

// 导入内置模块和第三方模块是不需要加路径【查找机制:现找本地node——modules文件夹,如果找不到这个模块,再去内置模块中找...】
let fs = require('fs'),
    path = require('path'),
    qs=require('qs');
// 导入自定义模块一定要加路径[js后缀可以省略]
let A=require('./1');

node模块

  • __dirname:当前文件的绝对路径
  • __filename:当前文件绝对路径下的文件名

path模块

path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径

let path = require('path');
console.log(path.resolve(__dirname,'dist'));// \Users\...REACT\0707\dist
console.log(path.resolve('/foo/bar','dist'));// \foo\bar\dist
console.log(path.resolve('/foo/bar','../dist'));// \foo\dist

fs内置模块

FS内置模块:赋予了JS操作I/O的能力

  • readFile / readFileSync 读取文件的全部内容
  • readdir / readdirSync 读取目录的内容
  • mkdir / mkdirSync 创建目录
  • rmdir / rmdirSync 删除目录
  • unlink / unlinkSync 删除文件
  • writeFile / writeFileSync 将数据写入文件
  • appendFile / appendFileSync 将数据附加到文件

同步读取文件内容【阻碍式I/O操作:内容没有读取完成,其他的代码都不能进行】

  • 默认获取的是Buffer格式的数据【文件流、文件编码】
  • 配置项设置成utf-8,则获取的是文本格式数据【文本字符串】
let data= fs.readFileSync('./package.json','utf-8');
console.log(data);

异步读取文件内容:方案一

fs.readFile('./package.json','utf-8',function(err,data){
    // 读取成功或者失败都会触发这个回调函数
    //  + 如果读取失败,err存储的是失败的信息
    //  + 读取成功,data存储的是读取的内容
    if(err){
        console.log(`很遗憾,读取信息失败,错误原因:${err.message}`);
        return
    }
    console.log(data);
});
console.log('ok');

异步读取文件内容:方案二:基于promise管理

  • 读取文件成功,返回的promise实例就是成功,反之就是失败
let fs = require('fs'),
fsPromise = fs.promises;

fsPromise.readFile('./package.json','utf-8').then(data=>{
    console.log('请求成功',data);
}).catch(err=>{
    console.log('请求失败',err);
})

二、Express基础知识及应用【node框架】

node中常用的框架

  • express[入门级]
  • koa2
  • egg

后台要处理的事情

  • @1创建一个服务【设定端口号,来区分不同服务】
  • @2处理客户端资源文件
  • @3处理客户端数据请求
  • 创建Web服务器:完成对静态资源文件的请求处理
  • 创建数据服务器:完成对API接口的请求处理

创建web服务器【静态资源处理】

let express = require('express'),
    app = express(),
    PORT = 9999;
app.listen(PORT, () => {
    // 当WEB服务创建成功,并且成功监听了端口号,触发这个回调函数
    console.log(`web service has been created successfully, listening for port number:${PORT}`);
});

// 处理静态资源文件的请求
//   + app.use:让当前创建好的服务使用中间件
//   + express.static([path]):处理静态资源文件请求的中间件
//      + [path]:以后向当前服务器发送请求,我们去哪个目录中找资源
app.use(express.static('./static'));
app.use((req, res) => {
    // 当请求的资源不存在,就会走到这里
    
    //  + req「request」请求对象,包含了客户端发送过来的请求信息
    //    + req.body 结合body-parser中间件,可以获取客户端传递的请求主体信息
    //    + req.headers 获取请求头信息「也可以:req.get('xxx')」
    //    + req.query 获取URL问号传参信息
    //    + req.path: 存储请求地址的路径名称
    //    + req.method: 请求方式
    //    + ...
    
    //  + res「response」响应对象,提供一系列的方法,让服务器端把信息返回给客户端
    //    + res.status(code) 设置服务器返回的HTTP状态码
    //    + res.set([key],[value]) 设置响应头信息
    //    + res.send() 设置响应主体信息「格式:字符串、对象(内部会变为JSON格式字符串返回给客户端)、Buffer...」
    //    + res.json: 返回给客户端内容,值不过传递的数据可以是json对象(内部会帮我们把其转换为json字符串 => 服务返回给客户端的内容一般都是字符串或者buffer格式)
    //    + res.type: 返回content-type的类型值
    //    + ...
    res.status(404);
    res.send('the requested resource does not exist!');
});

创建数据服务器【接口请求处理】

let express = require('express'),
    app = express(),
    PORT = 9999;
app.listen(PORT, () => {
    // 当web服务创建成功,并且成功监听端口号,触发这个回调函数
    console.log(`Web service has been created successfully, listening for port number:${PORT}`);
});
// 中间件:提取请求的公共逻辑,在所有处理之前先干的事

/* app.use((req, res, next) => {
    // 只针对post请求
    if (/^(POST|PUT|PATCH)$/i.test(req.method)) {
        let data = '';
        req.on('data', chunk => data += chunk);
        req.on('end', () => {
            // 把获取的请求主体信息挂到req.body上
            let qs = require('qs');
            req.body = qs.parse(data);
            next();
        })
        return;
    }
    // 不是POST请求,直接向下处理
    next();
}) */

// 现成的中间件
let bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
    extended: true
}));



// ============================
// API请求
// 1.GET /list?lx=pro/dev 我们把package.json中的开发/生产依赖信息返回
// 2.POST /create 请求主体:name=zhufeng&age=12 返回{code:0,body:{name:zhufeng,age:12}}
let fs = require('fs').promises;
app.get('/list', async (req, res) => {
    let {
        lx,
    } = req.query;

    let data = await fs.readFile('./package.json', 'utf-8');
    data = JSON.parse(data);
    res.send(lx === 'dev' ? data.devDependencies : data.dependencies);
});

/* //没使用中间件之前的代码
let qs = require('qs');
app.post('/create', (req, res) => {
   /*  // 接收主体信息
    let data = '';
    req.on('data', chunk => {
     //=>正在分批接收客户端传递的请求主体信息 CHART:当前接收的部分
        data += chunk;
    });
    req.on('end', () => {
        // data存储的是请求主体信息
        data = qs.parse(data);
        res.send({
            code: 0,
            body: data
        });
    }); 
}); */

app.post('/create', (req, res) => {
    res.send({
        code: 0,
        body: req.body
    })
});


app.use(express.static('./static'));
app.use((req, res) => {
    res.status(404);
    res.send(`The requested resource does not exist!`)
})


使用中间件

let express = require('express'),
    app = express(),
    PORT = 9999;
app.listen(PORT, () => {
    console.log(`Web service has been created successfully, listening for port number:${PORT}`);
});
// 中间件:提取请求的公共逻辑,在所有处理之前先干的事

/* app.use((req, res, next) => {
    // 只针对post请求
    if (/^(POST|PUT|PATCH)$/i.test(req.method)) {
        let data = '';
        req.on('data', chunk => data += chunk);
        req.on('end', () => {
            // 把获取的请求主体信息挂到req.body上
            let qs = require('qs');
            req.body = qs.parse(data);
            next();
        })
        return;
    }
    // 不是POST请求,直接向下处理
    next();
}) */

// 现成的中间件
let bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
    extended: true
}));


// API请求
// 1.GET /list?lx=pro/dev 我们把package.json中的开发/生产依赖信息返回
// 2.POST /create 请求主体:name=zhufeng&age=12 返回{code:0,body:{name:zhufeng,age:12}}
let fs = require('fs').promises;
app.get('/list', async (req, res) => {
    let {
        lx,
    } = req.query;

    let data = await fs.readFile('./package.json', 'utf-8');
    data = JSON.parse(data);
    res.send(lx === 'dev' ? data.devDependencies : data.dependencies);
});

app.post('/create', (req, res) => {
    res.send({
        code: 0,
        body: req.body
    })
});


app.use(express.static('./static'));
app.use((req, res) => {
    res.status(404);
    res.send(`The requested resource does not exist!`)
})

使用路由

// server.js
app.use('/user', require('./routes/user'));

// routes/user.js
let express = require('express'),
    route = express.Router(); //=>ROUTE就是创建的一个路由,用法和APP一样

route.get('/list', (req, res) => {
    ...
});

module.exports = route;

image.png

三、常见的API功能接口实现