avatar

Catalog
node

what‘s node?

node既不是一种语言,也不是一个框架,更不是一个库。而是一种能让JavaScript运行在服务器上的一个平台

首先要下载node.js 自行到官网中下载。注意两个版本的区别

node中是以模块来划分作用域

node里面分为两个作用域,全局作用域(glogbal)和模块作用域

  • require(’模块标识符’) —–我们需引入模块需要用到的方法

  • 模块

    • 用户自定义模块—-自己定义的一个js文件模块
    • 系统提供模块—例如:fs,http…

例如我们想要读取一个txt文件,JavaScript中是不可能实现的

javascript
let fs = require('fs')
//如果读取成功,则返回一个回调函数,erro----null,data----一串16进制,否则的话,erro----报错,data---undefined
fs.readFile('txt路径',(erro,data)=>{
console.log(erro)
console.log(data)
//如果想要获取文件中的内容,只需要把16进制转换为字符串即可
console.log(data.toString())
});
  • 基本上路径如果,对的话是没有问题的,还有可能文件不存在。
现在我们不止想要读一个文件,我还想写入一个文件
javascript
let fs = require('fs')
fs.writeFile('路径','文件内容',error=>{
//写入文件,如果成功则 error为null null又默认为0
if(error){
console.log('文件写入失败')
}else{
console.log('文件写入成功')
}
})

http模块

javascript
//引入http模块
let http = require('http')
//创建服务器
let server = http.createServer((req,res)=>{
url = req.url
//查找url
if(url === '/'){
res.end('http 的使用')
}
})
//开启服务器
server.listen(3000,()=>{
console.log('running is server...')
})

exports和module exports的区别

很多时候我们需要引入到别的模块中的变量,这个时候我们就需要使用的exports或者module.exports来暴露我们需要使用的变量或者对象。每一个模块中都有一个module.exports对象,每一个module.exports对象都有一个exports对象,所以我们把需要暴露的对象都挂载在module.exports对象上。所以每次暴露都是module.exports.xxx = xxx但是为了方便同时又在每一个模块中提供了一个exports成员,还有exports === module.exports是为true假如我们只需要暴露xxx我们可以直接exports.xxx即可

如果我们暴露单个成员则需要使用module.exports不能使用exports因为最终返回的都是module.exports即使exports=xxx也不行,

但是有一种特别的特殊方法 exports=module.exports是可以的,

多次暴露使用exports

单次暴露使用module.exports

module.exports也可以多个暴露(module.exports={}即可)

Express

一、安装express框架(npm i -S express)

  • 引入express模块
  • 定义变量接受express()方法

利用express实现helloworld

javascript
let express = require('express')
let app = express()
//使用路由
app.get('/',(req,res)=>{
res.send('hello world')
})
//使用路由
app.get('/login',(req,res)=>{
res.send('login')
})
//开启服务器
app.listen(3000,()=>{
console.log('server is running')
})

总的来说比我们之前写原生简单易懂的多。

二、nodemon的使用

每一次修改完代码是不是每一次都要node app.js 还要每一次都要开启服务器。nodemon是我们每一次修改完代码后只要ctrl+s然后刷新浏览器就可以更改。

  • npm i -g nodemon(安装nodemon)
  • nodenom -v (查看版本号)
  • nodemon xxx.js(运行js文件)

三、模板引擎的使用

  • 先下载art-template
  • 使用engine(’以什么文件后缀’,’express-art-template’)引入express-art-template包
  • 使用路由get()方式
  • 使用render(‘渲染的文件’,{对象数据}) 默认到views文件夹中去寻找,若要修改则app.set(‘views’,’文件夹路径’)
javascript
let express = require('express')
let app = express()
app.engine('html',require('art-template-express'))
app.get('index.html',(req,res)=>{
res.render('index.html')//没有数据就无需写第二个参数
})

//配置插件开始
let bodyParser = require('body-parser')
//配置body-parser
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
//插件配置结束

//使用get方法获取数据,这个/pinglung是表单的action='/pinglun',methond='get'
app.get('/pinglun',(req,res)=>{
let comment = req.query
comment.dataTime = '2019-5-1'
comments.unshift(comment)
res.redirect('/')
})
// 使用post方法获取数据需要借助中间的插件body-parser才可以获取数据,不想get有一个内置的api (req.query),需要借助第三方插件,还需要配置
app.post('/post',(req,res)=>{
let comment = req.body
comment.dataTime = '2018-3-5'
comments.unshift(comment)
res.redirect('/')//重定向
})

四、提取路由模块

我们每一次写路由的时候都会用很多的页面,那么这个时候都写在app中似乎有些不妥,这个时候我们可以把路由模块单独提取出来,生成一个router.js 而app.js只作为入口文件,具体操作如下。

app.js

javascript
let express = require('express')
let app = express()
//加载用户自定义router.js模块
let router = require('./router')
//使用路由
app.use(router)
app.listen(3000,()=>{
console.log('server is running')
})

router.js

javascript
let express = require('express')
//路由都挂载在router上
let router = express.Router()
router.get('/',(req,res)=>{
res.send('index')
})
router.get('/login',(req,res)=>{
res.send('login')
})
router.get('/register',(req,res)=>{
res.send('register')
})
//导出路由,以后任何的入口文件要使用路由,都可以使用
module.exports = router

把路由与入口文件这个样子就可以彻底分开,这样感觉显得更加整洁。

五、静态资源库的开放

在这里我们首先来看path模块中的join函数和dirname与basename

  • __dirname——–针对与当前文件目录(没有当前文件的名字和扩展名)(动态的)
  • __basename——–当前文件的名字和扩展名(动态的的)

  • join(’c:\project\’,’\foo’)———–返回值c:\project\foo(将两个路径拼接在一起)

javascript
let path = require('path')
//要使用/public这个文件夹下的文件,开放当前路径下的/public文件夹中的所有文件
app.use('/public',express.static(path.join(__dirname,'/public')))

六、MongoDB

1、准备工作

(1)安装

在官网中下载安装包

分为,完整安装和自定义安装(只要改个路径就行了)一般我们选择完整安装

(2)配置环境变量

完整安装一般默认是放在C盘目录下

(3)测试是否安装成功

一般如果我们在bin目录下直接点击mongod.exe会出现闪退,这也是我们为什么要配置环境变量的原因。

如果出现以上的信息那么就代表我们安装成功。

(4)开启数据库
javascript
# 
mongod 默认使用时会把mongod根目录盘中的/data/db作为数据存储目录
//开启数据库
在命令行中输入
mongod

attention: 在第一次开启数据库的时候我们必须要在盘符根目录下(我的是c盘)新建一个/data/db两个文件夹下,不然就会出现连接不成功(shutting down)

修改默认路径:mongod –dbpath=数据存储目录

如果新建了文件夹,则会success(看不懂吧。。是的)

(5)关闭数据库
ctrl加c或者点击上面的叉即可

2、连接数据库

(1)默认连接本地数据库
Code
mongo
(2)在连接的时候退出数据库
Code
exit
(3)基本命令
  • show dbs
    • 显示所有数据库名称
  • use “数据库名称”

    • 如果有该数据库则切换到,如没有则新建一个数据库
  • db

    • 查看当前使用的数据库
  • show collections
    • 查看当前数据库中的所有的集合
  • show.[collections].find()
    • 查看数据库中集合的所有数据

这里需要说明一下,如果直接db的话,会出现test,但是我们show dbs的时候却没有test这个数据库,这是怎么回事呢?这个原因是因为我的test的数据库中没有数据,如果插入数据的话,再show dbs的话,则会出现test数据库(任何一个空的数据库都是这样,除非里面有数据,否则的话不会出现)

举个例子吧(假设下面的是终端)

Code
//创建或者切换数据库
use itcast
//向当前数据库中插入一个集合并且插入数据
db.students.insertOne({"name":"jack"})
//查看数据库(插入成功的话就会有这个数据库,相反却没有)
show dbs
//查看当前数据库的集合(应该会是students)
show collections
//查看当前集合中的所有元素({ "_id" : ObjectId("5ca346b9b0e4018e76041ca1"), "name" : "jack" })
db.students.find()

3、MongoDB基本概念

看到黑马视频一个描述MongoDB的挺有意思的:

  • 最外层的括号相当于MongoDB
  • qq,taobao,baidu。。相当于我们里面有很多数据库
  • user,product。。相当于数据库中的集合
  • name,age集合中的记录
javascript
{
qq:{
user:[
{"name":"张三",age:15},
{"name":"张三34",age:25},
{"name":"李四",age:35},
{"name":"张三34",age:45},
....
],
product:[
....
],
},
taobao:{
...
},
baidu:{

}

}

4、使用mongoose操作mongodb

(1)安装mongoose包(npm i mongoose)

(2)引入mongoose模块 (let mongoose = require(mongoose))

(3)创建架构

(4)连接数据库

(5)设计结合的结构

(6)将文档结构发布为模型

javascript
//2
let mongoose = require('mongoose')
//3
let Schema = mongoose.Schema
//4
mongoose.connect('mongoose://localhost/数据库名称')
//5
//里面的字段就是集合结构中的属性名称
//约束的条件是为了防止有脏数据
let userSchema = new Schema({
username: {
type: String,
required: true,//必须有该属性
},
password: {
type: String,
required: true
},
email: {
type: String
}
})
//将文档结构发布为模型
/*
第一个参数,大写的单数字符串作为你的数据库名称,mongoose会自动将你的数据库名称转换为小写复数集合名称
列如这里的User最终会变成users集合名称
第二个参数,架构Schema

返回值:模型构造函数
*/
let User = mongoose.model('User',userSchema)

5、增加数据

javascript
let admin = new User({
username: 'zs',
password: '123456',
email: '3199895@qq.com'
})

admin.save((err,ret)=>{
if(err){
console.log('保存失败')
}else{
console.log('保存成功')
console.log(ret)
}
})

6、查询数据

javascript
//查询所有的数据
User.find((err,ret)=>{
if(err){
console.log('查询失败')
}else{
console.log(ret)
}
})
//查询符合记录的数据
User.findOne({
username: 'zs'
},(err,ret)=>{
if(err){
console.log('查询失败')
}else{
console.log(ret)
}
})

7、删除数据

javascript
//删除数据
User.remove({
username: 'zs'
},(err,ret)=>{
if(err){
console.log('删除失败')
}else{
console.log(ret)
console.log('删除成功')
}
})

8、更新数据

javascript
//更新数据 id,修改内容,名称

User.findByIdAndUpdate('5ca35aaa914afc2efceed812',{
password: '123456'
},function(err,ret){
if(err){
console.log('更新失败')
}else{
console.log(ret)
console.log('更新成功')
}
})

第二篇

对象

  • 全局对象:随时都能访问
    • process.env
    • __filename(获取当前运行文件的绝对路径)
    • __dirname(获取当前运行文件目录的绝对路径)
  • 内置对象:向系统索要,引入即可
  • 自定义对象:引入正确的路径即可

node所实现的规范

  • CommonJS:规范nodeJS作为后端运行的标准
    • 模块应该怎么写module
      • 依赖某一模块require
      • 被依赖的模块需要module.exports = 外部数据
    • 一个文件就是一个模块

文件的读取和写入

如果要对文件进行操作,就要先引入文件模块fs

  • readFile(文件路径和名,’utf-8’,回调函数)异步读取文件的内容
  • readFileSync()同步读取文件的内容
  • writeFile(文件的路径和名,文件内容,回调函数)
javascript
const fs = require("fs");
fs.readFile("./public/a.txt","utf-8",(err,data)=>{
if(err) throw err;
console.log(data);
})
fs.writeFile("./public/b.txt","哈哈哈,几天也是很难熬的一天啊",(err)=>{
if(err) throw err;
console.log("写入文件完成");
})

http

http是node中的核心模块,同样的要先引入

  • createServer()创建一个本地的服务器
  • http.on()执行request请求,并有一回调函数,获取到request和,response参数。
    • request是只读不能写入
    • response是可以写入
  • http.listen(端口号,回调函数)用以开启服务器
javascript
const http = require('http')
const port = process.env.PORT | 3000
http.createServer((req,res)=>{
// 多次写入 写头
res.setHeader('a','a')
res.setHeader('c','c')
// 一次性写入,一定在多次写入的后面
res.writeHead(200,{'content-type':'text/html;charset=utf-8'})
//多次写体
res.write('第一次写入')
res.end('最后一次写入')
})
.listen(port,()=>{
console.log(`server is running ${port}`)
})

状态码

  • 1开头正在执行
  • 2开头已完成
  • 3开头重定向
  • 4开头客户端出现错误
  • 5开头服务端出现错误

连接Mysql数据库

  • npm i mysql -g(全局下载项目依赖模块)
  • 复制对应代码
Code
var mysql = require('mysql');
var pool = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'node_music'
});
pool.connect()
let db = {}
db.q = function(sql,params){
pool.query(sql, params,function (error, results, fields) {
if (error) throw error;
else{
console.log('成功插入到数据库中')
console.log(results)
pool.end()
}
})
}
module.exports = db

KOA框架

主要介绍koa框架,express在上一篇文章已经介绍过了。koa框架是express的作者是同一个人,比起express(太大,太全)反而koa(轻量级,按需引入)

  • 引入koa
  • 创建一个koa对象
  • 处理响应
  • 开启服务器

koa是非常智能的,如果我们读一个二进制的文件,它会帮我们下载下来。

另外需要注意的是:koa采用的是es7中的async 和await需要和promise联合使用,废弃掉了express采用回调函数的机制

中间件的使用也是按需引入,比较方便

koa-bodyparser

javascript
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const app = new Koa()
app.use(bodyParser())
app.use( async ctx => {
ctx.body = ctx.request.body
})
const port = process.env.PORT || 3000
app.listen(port,()=>{
console.log(`server is running ${port}`)
})
  • 使用
javascript
const db = require('./db_test_01')
db.q(`insert into users (title,single,time,file,uid) values(?,?,?,?,?)`,['小菜','青花瓷','03:00','d:/',6])

koa-router**

  • npm i koa-router
  • 引入路由模块
  • 创建对象
  • 和app相关联
javascript
const Koa = require('koa')
const bodyParser = require('koa-bodyparser')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()

router.get('/',async ctx => {
ctx.body = '首页'
})
.post('/post',async ctx => {
ctx.body = ctx.request.body
})
app.use(router.routes())
app.use(bodyParser())
//优化状态码的处理405和501不再是单一的404
app.use(router.allowedMethods())

const port = process.env.PORT || 3000
app.listen(port,()=>{
console.log(`server is running ${port}`)
})

路由嵌套

koa中把路由模块单独抽离出来,是希望可以开发大型的企业项目,可以有多级的路由嵌套。

以下是我们的目录树:

├─03_koa_router
│ │ app.js

└─router
├─cat
├─new
└─user
admin.js
company.js
index.js

app.js中我们需要引入

javascript
router.use('/user',require('./router/user'))
app.use(router.routes())

index.js

koa-art-template**

  • 模板引擎
javascript
const Koa = require('koa')
const path = require('path')
const Router = require('koa-router')
const render = require('koa-art-template')
const app = new Koa()
const router = new Router()

render(app,{
//到view中去找
root: path.join(__dirname,'view'),
//后缀文件名
extname: '.html',
debug: process.env.NODE_ENV !== 'production'
})
router.get('/',async ctx => {
//使用render函数
ctx.render('index')
})
app.use(router.routes())
app.use(router.allowedMethods())

const port = process.env.PORT || 3000
app.listen(port,()=>{
console.log(`server is running ${port}`)
})

koa-static

这里面有点难以理解,我们只需要在上面的代码加上以下的两句代码即可,但是我们的index.html中的

//这里面不需要写目录文件夹名,一旦写就错了,如果写的话,我们需要判断

  • const static = require(‘koa-static’)
  • app.use(static(path.resolve(‘./js’)))

前端静态写了目录文件夹名称的需要进行判断

javascript
app.use(async (ctx,next) => {
if(ctx.url.startsWith('/js')){
//一般的request请求不能修改,但是例外
ctx.url = ctx.url.replace('/js','')
}
//无论满足不满足都应该放行
await next()
})

koa-session

  • 必须引入koa-session
  • 必须在路由挂载之前
  • 一般都为默认值,不修改
  • signed如果设置false

1563256801627

则别人会获取到,然后进行解密。再篡改就麻烦了,所以我们一般设置为true,这样就会有个签名和初始值是对应的,修改的话后台会报异常

  • httpOnly如果为true,我们客户端document.cookie就会获得到。反正不会
javascript
const Koa = require('koa')
const path = require('path')
const bodyParser = require('koa-bodyparser')
const Router = require('koa-router')
const render = require('koa-art-template')
const static = require('koa-static')
const session = require('koa-session')
const app = new Koa()
const router = new Router()

render(app,{
root: path.join(__dirname,'view'),
extname: '.html',
debug: process.env.NODE_ENV !== 'production'
})
router.get('/',async ctx =>{
ctx.render('index')
})
.post('/login',async ctx => {
let username = ctx.request.body.username;
let password = ctx.request.body.password;

if(username != "admin" || password != "123"){
ctx.throw(200,'有急事去啦~')
}else{
//在session中存放东西
ctx.session.user = {
username: 'admin'
}
ctx.body = '登录成功'
}
})
/加密算法字符串/
app.keys = ['some secret hurr']
const CONFIG = {
key: 'koa:sess', //cookie名称
maxAge: 86400000,
overwrite: true,
httpOnly: true, 不允许客户端修改cookie
signed: true, 数字签名,保证数据不被串改
rolling: false,过期时间顺延
renew: false, 是否开启一个新的
}
app.use(static(path.resolve('./js')) )
app.use(bodyParser())
app.use(session(CONFIG, app));
app.use(router.routes())
app.use(router.allowedMethods())


const port = process.env.PORT || 3000
app.listen(port,()=>{
console.log(`server is running ${port}`)
})

以上的方法并不能保证信息的安全性,并且cookie的值还会有长度限制,所以改用以下的方式,解不了密

javascript
app.keys = ['some secret hurr']
let store = {
storage: {},
get(key){
return this.storage[key]
},
set(key,sess){
this.storage[key] = sess
},
destroy (key) {
delete this.storage[key]
}
}
app.use(session({store}, app));

koa中出错处理

javascript
ctx.throw()//抛出异常



app.use(async (ctx,next) => {
try{
await next()
}catch(e){
ctx.status = 200
ctx.body = `<div>你访问的页面失联了</div>`
}
})

生成key

javascript
const fs = require('fs')
const key_len = 1024
const key_count = 2048
let char = 'idOFIGLSFGJKSFGfHSGFHusakjfds#¥#@6556aHGSFff{}D}{:SFJAfdsafJ*(……%5KFSdgfdasfkdsjDJF355435&*'
let arr = []
for(let i = 0; i < key_count; i++){
let key = ''
for(let j = 0; j < key_len; j++){
key += char[Math.floor(Math.random()*char.length)]
}
arr.push(key)
}
fs.writeFileSync('.keys',arr.join('/n'))
console.log(`get ${key_count}`)
Author: Yo
Link: https://powerlrl.gitee.io/2019/03/15/前端/笔记/node/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 谢谢你请我吃糖果
    谢谢你请我吃糖果

Comment