node基础-持续更新

node基础

  • 1.node模块
  • 2.node环境搭建
  • 3.fs模块
  • 4.ES模块和CommonJS模块
    • 4.1 更改后缀名
    • 4.2 package.json配置支持es模块
    • 4.3 变量别名
    • 4.4 CommonJS模块
  • 5.打造自己的脚手架工具
    • 5.1创建自定义全局指令
    • 5.2 使用commander处理--help参数
    • 5.3 处理自定义指令
    • 5.4 逻辑代码模块化拆分
    • 5.5 命令行问答交互
    • 5.6 下载远程仓库模板代码(download-git-repo)
    • 5.7 下载等待提示交互(ora)
    • 5.8 命令行样式输出(chalk)
  • 6. 原生node开发web服务器
    • 6.1 使用node创建http服务器
    • 6.2 服务器响应不同数据类型
    • 6.3 HTTP的不同请求方式的处理
    • 6.4 接收并处理POST消息数据
    • 6.5 服务器代码模块拆分
  • 7. express框架
    • 7.1 Express项目构建
      • 7.1.1 空框架(自己拓展)
      • 7.1.2 快速创建 Express.js 应用程序骨架
      • 7.1.3 之前的全局命令
    • 7.2 express框架基本使用
    • 7.3 express管理用户数据信息
    • 7.4 处理客户端post请求数据
    • 7.5 添加用户信息到db文件
    • 7.6 修改用户信息
  • 8.项目数据持久化存储
    • 8.1 MongoShell执行环境与客户端
      • 8.1.1 MongoShell执行环境
      • 8.1.2 第三方客户端连接mongoDb数据库
    • 8.2 mongoDb语法
    • 8.3 使用node连接mongoDb数据库
    • 8.4 使用node进行增删改查操作
  • 9. Express中间件和RESTful API接口规范
    • 9.1Express中间件的概念和基本使用
    • 9.2 不同的中间件类别的使用方法
      • 9.2.1应用程序级别中间件
      • 9.2.2 路由级别中间件
      • 9.2.3 错误中间件
      • 9.2.4 内置中间件
      • 9.2.5 第三方中间件
    • 9.3 Express路由与响应的方法
    • 9.4 项目基础设计搭建优化
      • 9.4.1 基础中间件
      • 9.4.2 路由模式
      • 9.4.3 路由的业务逻辑模块
    • 9.5 数据化处理模块-mongoose
    • 9.6 用户注册数据入库
    • 9.7 用户注册的密码加密问题

声明:自我学习记录
node模块大概可以说成三个模块,核心模块,第三方模块,自定义模块。
模块化可以避免变量名重复带来的影响

1.node模块

2.node环境搭建

3.fs模块

链接 链接,

4.ES模块和CommonJS模块

有两个文件,export.js和import.js,一个导出一个导入,

//export.js
let ex = 'exception'
export {ex}
//import.js
import { ex } from './import.js'
console.log(ex)

然后我们运行 node ./import.js,按逻辑来说应该是可以的。但是报错了的
在这里插入图片描述
node默认是不支持es模块的,支持的是commonJS,解决方法

4.1 更改后缀名

将文件的js后缀名改为mjs,且引入和执行都要改为mjs
在这里插入图片描述
但是不是每个都要将js后缀改为mjs,文件多了是不太可取的。所以还有种方法
这里穿插下,还有种导出export default


let ex = 'exception'
let ex1 = 'exception1'
export default {ex, ex1}
//这里的导出入就不能import {ex} from './export.mjs'
import ex from './export.mjs'console.log(ex)

在这里插入图片描述

4.2 package.json配置支持es模块

新建package.json,配置

{"type": "module"
}

那这里的node是关于ES模块的使用方法(import和export),那关于原来的CommonJS模块的导入导出(module.exports和require)也是有方法的

4.3 变量别名

导出和导入都可以使用as关键字,这种写法好像只适用于ES模块,为了避免变量名重复(导出的变量名会有和在导入的文件中重复的可能),要一一对应

//export.js
let ex = 'exception'
export {ex as ex1}
//import.js
import { ex1 as ex2 } from './import.js'
console.log(ex2)

4.4 CommonJS模块

CommonJS每个模块都会有一个module,打印出来看一下

在这里插入图片描述
导出的写法是


let ex = 'exception commonjs'
let ex1 = 'exception commonjs1'//这种写法只能导出一个变量,不可取有点
// module.exports = ex
// module.exports = ex1// module.exports.ex = ex
// module.exports.ex1 = ex1module.exports = {ex,ex1
}// exports.ex = ex
// exports.ex1 = ex1  //这里不能这样写,不然只会导出为null
// exports ={
//     ex,
//     ex1
// }
console.log(module)

5.打造自己的脚手架工具

5.1创建自定义全局指令

目录下新建bin文件夹,文件夹下有cli.js文件
在这里插入图片描述
接着在bin目录的上级目录下,命令终端npm init
在这里插入图片描述先创建目录再npm init是因为这样初始的package.json文件下,会多一个配置
在这里插入图片描述
然后再执行npm link,把当前的命令行挂载到全局命令行工具中
在这里插入图片描述

这里要把上面的package.json的"mycli": “cli.js"改成"mycli”: “bin/cli.js”,不然会报错
在这里插入图片描述
改一下,把"mycli": “cli.js"改成"mycli”: “bin/cli.js”,然后再npm link,最后再执行mycli
在这里插入图片描述
在cmd下执行
在这里插入图片描述
但是如果在编辑器的终端执行mycli指令,会报错的!
在这里插入图片描述
解决方法:
以管理员身份打开windows PowerShell,运行Set-ExecutionPolicy RemoteSigned
在这里插入图片描述
最后在Vscode终端再执行mycli,可行
在这里插入图片描述

如果我们在指令后加入参数,想获取的话需要用到process.argv

#!/usr/bin/env node
// console.log("Starting server...")
console.log(process.argv)

结果
在这里插入图片描述

是个数组,第一个是使用的那个脚本执行的代码,第二个是我们代码的位置,最后一个就是我们输入的参数

5.2 使用commander处理–help参数

每个全局指令指令都会有–help,我们用commander来实现自己的脚手架–help功能。

npm install commander

直接使用

#!/usr/bin/env node
// console.log("Starting server...")
// console.log(process.argv)
//使用commander
const { program } = require('commander')program.option('--first').option('-f --framnework <framework>', '设置框架').option('-s, --separator <char>');program.parse(process.argv);

然后运行mycli --help,报错了!
在这里插入图片描述
node版本太低了,原来是14.15.1后面变成了18.14.2,再来一遍
在这里插入图片描述

5.3 处理自定义指令

我想要实现的是输入mycli create XXX,给我初始化一个代码仓库结构。

#!/usr/bin/env node
// console.log("Starting server...")
// console.log(process.argv)
//使用commander
const { program } = require('commander')program.option('--first').option('-f --framnework <framework>', '设置框架').option('-s, --separator <char>');//自定义指令program.command('create <framework> [other...]').alias('crt') //第二种形式 命令简写.description('创建项目') //命令描述.action((framework, args) => {console.log(framework, args)})//接收后执行的工作program.parse(process.argv);

执行后的结果:
在这里插入图片描述

5.4 逻辑代码模块化拆分

上面的代码告诉我们之后的逻辑就该写在action方法里,但是我们自己的脚手架可能需要做文件的新建,代码的拉取等等事情,写在一起太复杂,所以逻辑代码模块化拆分很重要。
代码提交

5.5 命令行问答交互

接下来就可以进行命令行问答交互了,需要使用到Inquirer。代码提交

const inquirer = require('inquirer');
let frameConfigs = require('../../frameConfig')
const myaction = (project, args) => {inquirer.prompt([{type: 'list',name: 'framework',choices: frameConfigs.frameworks,message: '请选择你要使用的框架'}]).then(answer => {console.log(answer)})}module.exports = myaction

最后运行会报错,最新的inquirer的版本是9.2.2,使用的是node的ES模块,但是我的项目是CommonJS模块,给inquirie降级,降到8.1.0

在这里插入图片描述
最后实现的效果
在这里插入图片描述

5.6 下载远程仓库模板代码(download-git-repo)

需要使用到download-git-repo,专门下载仓库模板代码提交

let download = require('download-git-repo');
let {frameworksMap} = require('../../frameConfig')
const downloadFun = (answer, project) =>{download(`direct:${frameworksMap.get(answer.framework).cloneAdress}`, project, {clone: true}, function (err) {console.log(err ? 'Error' : 'Success')})
}
module.exports = downloadFun;

5.7 下载等待提示交互(ora)

再给下载过程中加一个下载等待提示的交互告诉用户下载进度。ora插件,下载5系列的版本,6版本的方式为ESmodule了,我们用CommonJS模块。npm i ora@5。代码提交

let download = require('download-git-repo');
let {frameworksMap} = require('../../frameConfig')
const ora = require('ora')const downloadFun = (answer, project) =>{const spinner = ora('代码下载中...').start();download(`direct:${frameworksMap.get(answer.framework).cloneAdress}`, project, {clone: true}, function (err) {if(err){pinner.fail('下载失败')}else{spinner.succeed('下载成功');console.log('Done! you can run:')console.log('cd  '+ project)console.log('npm install')console.log('npm run dev')}})
}
module.exports = downloadFun;

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

5.8 命令行样式输出(chalk)

同理,CommonJS模块是最多4版本,npm i chalk@4代码提交

let download = require('download-git-repo');
let {frameworksMap} = require('../../frameConfig')
const ora = require('ora')
const chalk = require('chalk');const downloadFun = (answer, project) =>{const spinner = ora('代码下载中...').start();download(`direct:${frameworksMap.get(answer.framework).cloneAdress}`, project, {clone: true}, function (err) {if(err){pinner.fail('下载失败')}else{spinner.succeed('下载成功');console.log(chalk.blue('Done! you can run:'));console.log(chalk.blue('cd ')+ chalk.blue(project));console.log(chalk.blue('npm install'));console.log(chalk.blue('npm run dev'));}})
}
module.exports = downloadFun;

结果:
在这里插入图片描述
接下来就可以node的继续学习了。

6. 原生node开发web服务器

在这里插入图片描述

6.1 使用node创建http服务器

代码提交

let http = require('http');//创建服务器
let server  = http.createServer()
//监听端口
server.listen(8080,function(){console.log('Server running at http://127.0.0.1:8080/');
})
//为服务器上的 'request' 事件设置一个事件监听器。每当有新的 HTTP 请求到达服务器时,都会触发这个事件
server.on('request',function(req,res){res.write('8888')res.end()// res.writeHead(200,{'Content-Type':'text/plain'});// res.end('Hello World\n');
})
// http.createServer(function(req,res){
//     res.writeHead(200,{'Content-Type':'text/plain'});
//     res.end('Hello World\n');
// }).listen(8888,function(){
//     console.log('Server running at http://127.0.0.1:8888/');
// });

6.2 服务器响应不同数据类型

如果我们 res.write(‘8888你好’),页面上显示的却是
在这里插入图片描述
好像乱码了似的。

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

但是如果返回的是html代码呢

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

如果返回的html有img静态资源
在这里插入图片描述
页面是不会显示图片的,只会再发出一个请求
在这里插入图片描述
改一下代码

 if(req.url === '/'){fs.readFile('./test.html','utf-8', function(err,data){if(err){res.end('404')}else{res.write(data)res.end()}})}else{fs.readFile('./demo.png', function(err,data){if(err){res.end('404')}else{res.write(data)res.end()}})}

代码提交

6.3 HTTP的不同请求方式的处理

在这里插入图片描述
通过req的mothod来判断是哪种类型的请求。例如像get请求,http://127.0.0.1:8088/user?id=123的请求路径,我们肯定是还要获取到他的参数,使用req.url可以看到
在这里插入图片描述
是一个字符串,我们当然可以通过正则匹配来获取到对应的参数。但是,这里我们引入node的另外一个核心模块url。

console.log(url.parse(req.url))

结果:
在这里插入图片描述
好像返的还是只有字符串,改一下原来的代码

console.log(url.parse(req.url, true))

再看结果:
在这里插入图片描述
这时的query就有我们传的值了!代码提交

6.4 接收并处理POST消息数据

post请求的参数数据不是在url上的,node官网对http模块有个说明

为了支持所有可能的 HTTP 应用程序,Node.js HTTP API 非常低级。它仅处理流处理和消息解析。它将消息解析为标头和正文,但不解析实际的标头或正文。

这里就要使用到更底层的核心模块net,http模块是构建在net模块之上的。

else if (req.method === 'POST') {console.log('收到了post请求')//接收post的参数,使用到net模块//每当有数据来到服务器就会触发req.on('data', function (data) {console.log('DATA', data)})res.end('123')}

获取到的结果:
在这里插入图片描述
这是一个流数据,结束时转义;这里刚开始不太理解为什么要拼起来,处理一些大的文档可能会陆续传 所以拼起来最好

else if (req.method === 'POST') {console.log('收到了post请求')//接收post的参数,使用到net模块//每当有数据来到服务器就会触发//    req.on('data', function (data) {//     console.log('DATA', data)//    })let data = ''req.on('data', function (d) {data += d})req.on('end', function () {console.log('END', require('querystring').parse(data))});res.end('123')}

最后的结果:
在这里插入图片描述
拿到了post请求的数据。代码提交

6.5 服务器代码模块拆分

将server.js拆分为router.js(控制url请求的判断)和controller.js(不同url请求路径的业务代码)
代码提交
总结,这里也只是简单的一些请求url的小示例,正常的开发情况很多,我们应该把注意力更多的放在业务逻辑上,这种可以使用些基于node.js的web框架。

7. express框架

用途
在这里插入图片描述

7.1 Express项目构建

7.1.1 空框架(自己拓展)

npm init ;npm i express

7.1.2 快速创建 Express.js 应用程序骨架

npx express-generator

7.1.3 之前的全局命令

mycli create XXX,记住node版本要高一点(我用的是18.14.2)

代码提交

7.2 express框架基本使用

在express-fm文件夹下建app.js

const express = require('express');
const app = express();app.get('/', (req, res) => {})
app.post('/', (req, res) => {});
app.listen('3000', function(){console.log('listening on http://localhost:3000');
})

7.3 express管理用户数据信息

使用express来写接口的返回,

app.get('/', (req, res) => {fs.readFile('./dbas.json', 'utf-8', (err, data) => {if (!err) {res.send(data);} else {res.status(500).send(err)         }})
})

原生的是res.end,express是send!!!
有个问题,readFile后的回调如果是有连续好几个读写等操作甚至更多的话,回调会越写越多,不直观还可能会看错代码结构。这里引入express的promisify的。

const fs = require('fs');
const {promisify
} = require('util')
const readFile = promisify(fs.readFile)
app.get('/', async(req, res) => {try {let back =await readFile('./dba.json', 'utf-8')res.send(back)} catch (error) {res.status(500).send(error)}
})

代码提交
总结:express的基本使用,res.send,promisify的使用

7.4 处理客户端post请求数据

app.use(express.urlencoded());
app.use(express.json());
app.post('/', (req, res) => {
console.log(req.body) //这里打印出来的是undefined,因为post的请求content-type有很多种。浏览器在没有的情况下是无法解析的
console.log(req.headers) //这里可以看到content-type是application/x-www-form-urlencoded,我们就用到express的urlencoded()方法 app.use(express.urlencoded());//一般的post请求都是传的json数据的,我们用postman传一个json数据,发现打印出来的传参是个空对象{}
//这里我们就要用到express的json方法了 app.use(express.json());});

提交记录
总结:处理post的请求,req.body,req.headers等都要根据post的content-type的类型来看,使用到express.json()和express.urlencoded()

7.5 添加用户信息到db文件

上面只是处理拿到了post请求的入参等,post请求一般是用来修改,新增数据的,还差逻辑部分,补充完整。
代码提交

7.6 修改用户信息

put请求,主要用于向指定的URL上传送数据,通常用于更新资源或创建新资源。与GET请求不同
采用put+body+raw发送请求,实现的就是找到id为4的用户信息并进行修改。

在这里插入图片描述
首先要拿到put请求类型的参数

app.put('/:id',async(req, res) =>{console.log(req.params.id)console.log(req.body)
})

接下来就是业务代码了。

app.put('/:id',async(req, res) =>{console.log(req.params.id)console.log(req.body)let id = req.params.idlet {name, age} = req.bodylet userObj =await readFile('./db.json', 'utf-8')let userIndex = userObj.users.findIndex(item => item.id == id)if(userIndex){if(name){userObj.users[userIndex].name = name}if(age){userObj.users[userIndex].age = age}try {let writeRes = await writeFile('./db.json',userObj)console.log(writeRes,11)if(!writeRes){res.send('修改用户信息成功')}} catch (error) {res.status(500).json({error})}}else{res.send('没有找到用户')}
})

代码提交
总结:express框架通过app.put(‘/:id’,async(req, res) =>{
console.log(req.params.id)
console.log(req.body)
})来获取到url的参数和传入的参数

8.项目数据持久化存储

下面就是数据库了,这次mongoDB。安装可以不讲,c盘安装,环境变量。

8.1 MongoShell执行环境与客户端

8.1.1 MongoShell执行环境

执行mongo,发现提示不是内部命令。下载的是7.0版本的mongodb了,应该是mongos。但是执行mongos的话,也报错
在这里插入图片描述
原因待定,用mongosh,直接官网下载,然后运行即可
在这里插入图片描述

8.1.2 第三方客户端连接mongoDb数据库

使用navicat premuim

8.2 mongoDb语法

use mytest //创建数据库 如果没有该数据库就创建数据库,但是如果不向里面新建集合(表),刷新是看不到新增的数据库的
db.cc.insert({x:1,y:2})  //向数据库的cc表里加入数据
db.dropDatabase() //删库show collections //查看有哪些集合(表)
db.ff.drop() //删除表//增加表数据 mongodb新增数据会自带一个不会重复的_id字段
db.cc.insert({x:1,y:2})
db.cc.insert([
{x:2,y:2},
{x:3,y:2}
])
db.cc.insertOne({x:4,y:2})
db.cc.insertMany([
{x:2,y:2},
{x:3,y:2}
])//删除表数据 删除没有delete!!!
db.cc.deleteOne({x:1})
db.cc.deleteMany({x:1})//修改表数据
db.cc.updateOne({x:2}, { $set:{z:2}
})
还有update和updateMany//查找表数据  没有findMany!!!
db.cc.find() //查全部
db.cc.find({x:2})  //x=2的全部
db.cc.find({x:{ $gt:2 }}) //x > 2的全部
db.cc.findOne({x:{ $gt:2 }}) // x > 2的一个

8.3 使用node连接mongoDb数据库

使用插件mongodb,mongodb数据库版本7

const { MongoClient } = require('mongodb');
// or as an es module:
// import { MongoClient } from 'mongodb'// Connection URL
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);// Database Name
const dbName = 'test';async function main() {// Use connect method to connect to the serverawait client.connect();console.log('Connected successfully to server');const db = client.db(dbName);const collection = db.collection('cc');// the following code examples can be pasted here...const findResult = await collection.find({}).toArray();
console.log('Found documents =>', findResult);
}main().then(console.log).catch(console.error).finally(() => client.close());

执行报错:TextDecoderFatal ??= new TextDecoder(‘utf8’, { fatal: true });SyntaxE
在这里插入图片描述
我的node版本太低了,是14.15.1,改成18.14.2,执行还是报错:
在这里插入图片描述
不清楚为什么报错,把localhost换成127.0.0.1又可以了
在这里插入图片描述
代码提交

8.4 使用node进行增删改查操作

将连接mongo和数据操作进行拆分。

const { MongoClient } = require('mongodb');
let client ;
const connectMongoDb = async function(url,dbName,collection){client = new MongoClient(url);await client.connect();const db = client.db(dbName);return db.collection(collection);
}
async function main() {const collection = await connectMongoDb('mongodb://127.0.0.1:27017','mytest','cc')const ins = await collection.insertOne({x:1,y:1}) //mongodb插件是没有insert方法的const del = await collection.deleteOne({x:1,y:1}) //const delMany = await collection.deleteMany({x:1,y:1})const update = await collection.updateOne({x:4,y:2},{ $set: {x:4,y:4}})// const updateMany = await collection.updateMany({x:1,y:1},{ $set: {x:2,y:2}})const findResult = await collection.find({}).toArray(); //查找要拿到结果 要 toArray一下
console.log('Found documents =>', findResult);
}main().then(console.log).catch(console.error).finally(() => client.close());

代码提交
总结:mongodb插件对mongo数据库的操作:
没有insert,delete,update方法的!!!!!!!查询是没有findMany方法的!!!

9. Express中间件和RESTful API接口规范

9.1Express中间件的概念和基本使用

express中间件可以理解成在原有流程中加一个步骤(例如图中的拆分清洗),而不影响整个流程。
在这里插入图片描述
理解中间件,我们可以想一个需求,在每次请求的时候记录一下他的日志简易版(请求方法,请求路径,请求时间),应该怎么做呢。没有中间件之前,我们会这么做。

app.get('/', (req, res) => {console.log(`${req.url} ${req.method} ${Date.now()}`)res.send('index')
})
app.get('/register', (req, res) => {console.log(`${req.url} ${req.method} ${Date.now()}`)res.send('register')
})
app.get('/home', (req, res) => {console.log(`${req.url} ${req.method} ${Date.now()}`)res.send('home')
})

再优化下

const log = (req) =>{console.log(`${req.url} ${req.method} ${Date.now()}`)
}app.get('/', (req, res) => {log(req)res.send('index')
})
app.get('/register', (req, res) => {log(req)res.send('register')
})
app.get('/home', (req, res) => {log(req)res.send('home')
})

但是也只是把方法提出去了,调用方法还是没有改变,如果请求很多的话,也要每个都去加这段代码。引出中间件

app.use((req,res) =>{console.log(`${req.url} ${req.method} ${Date.now()}`)
})

这样就可以了,中间件是每个请求流程都会去执行的。但是,postman的请求一直在请求中的状态,日志打印是有的
在这里插入图片描述
中间件还有第三个参数,如果不使用第三个参数的方法,是执行不到后面的响应里的。

app.use((req,res,next) =>{console.log(`${req.url} ${req.method} ${Date.now()}`)next()
})

而且,中间件的顺序位置是很关键的!!!!!!!如果放在接口请求的后面,是打印不出来日志的
代码提交
总结:中间件对每个请求流程都会起作用,中间件的next()和顺序位置很重要!!!

9.2 不同的中间件类别的使用方法

中间件类别可以分为:

  1. 应用程序级别中间件
  2. 路由级别中间件
  3. 错误处理中间件
  4. 内置中间件
  5. 第三方中间件

9.2.1应用程序级别中间件

这个就是上面的例子

app.use((req,res,next) =>{console.log(`${req.url} ${req.method} ${Date.now()}`)next()
})

这种也算

app.get('/', (req, res,next) => {console.log(555)next()
}, (req, res, next) => {console.log(666)next()
})

9.2.2 路由级别中间件

路由如果多了起来,全部在app.js里面,app.js还有其他的逻辑业务代码,会很乱。这里就要用到express.Router()进行分离

const express = require('express')const router = express.Router()router.get('/', function(req, res) {res.send('Hello World!')
})router.get('/rest', function(req, res) {res.send('rest')
})
module.exports = router

然后再引入即可

const express = require('express')
const app = express()
//路由级别中间件
const PORT = process.env.PORT || 3000
const router = require('./router')
app.use(router)
//app.use('/aaa',router) //可以给路由加上前缀
app.listen(PORT, () => {console.log(`Server is running at http://localhost:${PORT}`)
})

如果请求的路由没有在我们配置的内容里的话,会返回一个html内容
在这里插入图片描述
最好在使用路由中间件后再加入

app.use((req,res) =>{res.status(404).send('404 Not Found')
})

9.2.3 错误中间件

如果是路由中间件里出错了
在这里插入图片描述
在这里插入图片描述
这就需要用到错误中间件

//错误中间件
app.use((err, req, res,next) =>{console.log(err)res.status(500).send('Server Error')
})

9.2.4 内置中间件

express内置的,暂时用过的有express.Router()

9.2.5 第三方中间件

代码提交

9.3 Express路由与响应的方法

app.get post等请求都可以匹配路由 * + ? ,获取到参数 /user/:id req.params

// app.get('/user', (req, res) => {
//     console.log(`${req.method} ${req.url}`)
//     res.send('123')
// })
// app.get('/us?er', (req, res) => {
//     console.log(`${req.method} ${req.url}`)
//     res.send('123')
// })
// app.get('/us+er', (req, res) => {
//     console.log(`${req.method} ${req.url}`)
//     res.send('123')
// })
app.get('/us*er', (req, res) => {console.log(`${req.method} ${req.url}`)res.send('123')
})    //app.get post等请求都可以匹配路由 * + ? 
//获取到参数 /user/:id  req.params

响应的用得较多的目前就是 res.send(),res.status(),res.json()
代码提交

9.4 项目基础设计搭建优化

项目的基础搭建,
在这里插入图片描述

9.4.1 基础中间件

解析客户端请求中间件

app.use(express.json())
app.use(express.urlencoded())

跨域,cors

const cors = require('cors')
app.use(cors())

日志中间件,morgan

const morgan = require('morgan')
app.use(morgan('dev')) //开发环境下打印日志

9.4.2 路由模式

之前的路由是一个index.js文件

const express = require('express')const router = express.Router()router.get('/', function(req, res) {throw new Error('111')res.send('Hello World!')
})router.get('/rest', function(req, res) {res.send('resta')
})
module.exports = router

项目路由多了,首先路由看着就会很乱。。。
思路:在index.js里作为路由的整体模块入口,不同的路由类别在不同的同级js中,最后在app.js中引入
在这里插入图片描述
index.js

const express = require('express')const router = express.Router()router.use('/user',require('./user'))module.exports = router

user.js

const express = require('express');
const router = express.Router();router.get('/', function (req, res) {res.send('User API');
});
module.exports = router;

app.js

const router = require('./router')
// 挂载路由
app.use('/api/v1', router)

9.4.3 路由的业务逻辑模块

上面我们没有对路由的业务逻辑模块进行拆分,
在这里插入图片描述
controller下的index.js:

module.exports = {userList:async(req,res) =>{res.send('User API');}
}

router文件下的user.js:

const express = require('express');
const router = express.Router();
const {userList} = require('../controller/user');
router.get('/', userList);
module.exports = router;

代码提交

9.5 数据化处理模块-mongoose

const mongoose = require('mongoose');mongoose.connect('mongodb://127.0.0.1:27017/mytest').then(() =>{console.log('数据库连接成功')
}).catch((err) => {console.log('数据库连接失败',err)
})const Schema = mongoose.Schema;
const User = new Schema({name: { type: String },password: { type: String},date: { type: Date, default: Date.now },});const MyModel = mongoose.model('User', User);const u = new MyModel({ name: '张三1', password: '1234561' })u.save()

目前的代码感觉就是连接数据库,建表建数据可以。
代码提交

9.6 用户注册数据入库

model拆分,注册路由添加,逻辑代码添加
代码提交

9.7 用户注册的密码加密问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/20514.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iPad里的图片如何导出 iPad的照片如何管理

我们的设备中充满了各种重要的照片和视频&#xff0c;特别是iPad&#xff0c;作为苹果公司的一款强大的平板电脑&#xff0c;它不仅能够捕捉生活中的精彩瞬间&#xff0c;还可以存储和展示我们珍贵的回忆。然而&#xff0c;随着照片数量的不断增加&#xff0c;有效地管理和导出…

对boot项目拆分成cloud项目的笔记

引言&#xff1a;这里我用的是新版本的技术栈 spring-boot-starter-parent >3.2.5 mybatis-spring-boot-starter >3.0.3 mybatis-plus-boot-starter >3.5.5 spring-cloud-dependencies …

JVMの内存泄漏内存溢出案例分析

1、内存溢出 内存溢出指的是程序在申请内存时&#xff0c;没有足够的内存可供分配&#xff0c;导致无法满足程序的内存需求&#xff0c;常见的内存溢出情况包括堆内存溢出&#xff08;Heap Overflow&#xff09;和栈溢出&#xff08;Stack Overflow&#xff09;&#xff1a; …

AI去衣技术中的几何着色:揭秘数字时尚的魔法

在数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;正以前所未有的速度改变我们的生活&#xff0c;从智能家居到自动驾驶汽车&#xff0c;再到个性化医疗。然而&#xff0c;AI的影响远不止于此。它正在重塑我们对艺术、设计和时尚的理解。特别是在数字时尚领域&#…

Unity打包Webgl端进行 全屏幕自适应

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一&#xff1a;修改 index.html二&#xff1a;将非移动端设备&#xff0c;canvas元素的宽度和高度会设置为100%。三&#xff1a;修改style.css总结 下载地址&#x…

Solidity学习-投票合约示例

以下的合约有一些复杂&#xff0c;但展示了很多Solidity的语言特性。它实现了一个投票合约。 当然&#xff0c;电子投票的主要问题是如何将投票权分配给正确的人员以及如何防止被操纵。 我们不会在这里解决所有的问题&#xff0c;但至少我们会展示如何进行委托投票&#xff0c;…

《java数据结构》--详解Map和Set

概念 Map和set是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例化子类有关。在之前我们常见的搜索方式一般有两种&#xff1a; 一种是直接遍历&#xff0c;这种方法的时间复杂度为O(N)&#xff0c;如果元素比较多的话效率会十分低下另一种是…

Leecode---动态规划---打家劫舍 / 乘积最大子数组

动态规划法&#xff1a; 思路&#xff1a; &#xff08;1&#xff09;状态定义&#xff1a;dp[i]代表前i家能偷盗的最大金额 &#xff08;2&#xff09;状态初始化&#xff1a;如果只有一家&#xff0c;只能偷这家dp[0]nums[0]&#xff1b;如果有两家&#xff0c;因为是连通的&…

看图猜成语微信小程序源码

后台可以自行设置关卡、等级、也可以一键部署&#xff0c; 开通流量主之后实现躺赚&#xff0c;你懂得。 个人号也可以开通&#xff0c;审核一次性必过。 类目选择 教育&#xff0c;源码仅供您参考&#xff01; 源码下载 https://download.csdn.net/download/huayula/8938579…

【计算机毕业设计】基于SSM+Vue的网上花店系统【源码+lw+部署文档】

目录 目 录 1 绪论 1.1 选题背景 1.2 选题意义 1.3 研究内容 2 系统开发技术 2.1 Java语言 2.2 SSM框架 2.3 MYSQL数据库 2.4 Vue框架 3 系统分析 3.1可行性研究 3.1.1经济可行性 3.1.2时间可行性 3.1.3操作可行性 3.2系统性能分析 3.2.1系统易用性 3.2.2系统健壮性 3.2.3系统…

电脑没电关机,wsl和docker又挂了,附解决过程

如题&#xff0c;开了个会没带笔记本电源&#xff0c;点啊弄关机后docker打不开&#xff0c;我以为是docker坏了&#xff0c;结果docker报错&#xff1a; An unexpected error occurred while executing a WSL command. Either shut down WSL down with wsl --shutdown, and/or…

【蓝桥杯国赛】双指针

适用于以下的情境&#xff1a; ① 数组 / 字符串中&#xff0c;有多少个满足情况的连续区间。 ② 数组 / 字符串&#xff0c;合并。 【第十三届pythonB组试题&#xff1a;近似gcd】 1. 题目描述 2. 难度&#xff1a;⭐⭐⭐⭐ 3. 思考分析&#xff1a; 具体参考&#xff…

依据SAM大模型识别的英国农田(农业田野)边界(FIBOA)矢量数据集

简介 fiboa 是一项旨在提高农田边界数据互操作性和相关农业数据的合作计划。最近推出的 fiboa 不仅仅是一个规范&#xff0c;它还是一个全面的系统&#xff0c;包括符合规范的数据、不断完善规范的讨论以及积极促进其发展的活跃社区。本项目的重点是促进创建更多有关田地边界和…

黑马程序员——Spring框架——day03

目录&#xff1a; AOP AOP简介 问题导入AOP简介和作用【理解】AOP的应用场景为什么要学AOPAOP入门案例【重点】 问题导入AOP入门案例思路分析AOP入门案例实现AOP中的核心概念AOP工作流程【理解】 问题导入AOP工作流程AOP核心概念在测试类中验证代理对象AOP切入点表达式 问题导…

【python】爬虫记录每小时金价

数据来源&#xff1a; https://www.cngold.org/img_date/ 因为这个网站是数据随时变动的&#xff0c;用requests、BeautifulSoup的方式解析html的话&#xff0c;数据的位置显示的是“--”&#xff0c;并不能取到数据。 所以采用webdriver访问网站&#xff0c;然后从界面上获取…

C语言 指针——函数指针的典型应用:计算定积分

目录 梯形法计算函数的定积分 函数指针的典型应用 梯形法计算函数的定积分 函数指针的典型应用 用函数指针编写计算任意函数定积分的 通用 函数

Vivado 比特流编译时间获取以及FPGA电压温度获取(实用)

Vivado 比特流编译时间获取以及FPGA电压温度获取 语言 &#xff1a;Verilg HDL 、VHDL EDA工具&#xff1a;ISE、Vivado Vivado 比特流编译时间获取以及FPGA电压温度获取一、引言二、 获取FPGA 当前程序的编译时间verilog中直接调用下面源语2. FPGA电压温度获取&#xff08;1&a…

es的总结

es的collapse es的collapse只能针对一个字段聚合&#xff08;针对大数据量去重&#xff09;&#xff0c;如果以age为聚合字段&#xff0c;则会展示第一条数据&#xff0c;如果需要展示多个字段&#xff0c;需要创建新的字段&#xff0c;如下 POST testleh/_update_by_query {…

JVM学习-详解类加载器(一)

类加载器 类加载器是JVM执行类加载机制的前提 ClassLoader的作用 ClassLoader是Java的核心组件&#xff0c;所有的Class都是由ClassLoader进行加载的&#xff0c;ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部&#xff0c;转换为一个与目标类型对应的ja…